.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Catalyst::Manual::Tutorial::08_Testing 3pm" .TH Catalyst::Manual::Tutorial::08_Testing 3pm "2014-12-13" "perl v5.20.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Catalyst::Manual::Tutorial::08_Testing \- Catalyst Tutorial \- Chapter 8: Testing .SH "OVERVIEW" .IX Header "OVERVIEW" This is \fBChapter 8 of 10\fR for the Catalyst tutorial. .PP Tutorial Overview .IP "1." 4 Introduction .IP "2." 4 Catalyst Basics .IP "3." 4 More Catalyst Basics .IP "4." 4 Basic \s-1CRUD\s0 .IP "5." 4 Authentication .IP "6." 4 Authorization .IP "7." 4 Debugging .IP "8." 4 \&\fB08_Testing\fR .IP "9." 4 Advanced \s-1CRUD\s0 .IP "10." 4 Appendices .SH "DESCRIPTION" .IX Header "DESCRIPTION" You may have noticed that the Catalyst Helper scripts automatically create basic \f(CW\*(C`.t\*(C'\fR test scripts under the \f(CW\*(C`t\*(C'\fR directory. This chapter of the tutorial briefly looks at how these tests can be used not only to ensure that your application is working correctly at the present time, but also provide automated regression testing as you upgrade various pieces of your application over time. .PP Source code for the tutorial in included in the \fI/home/catalyst/Final\fR directory of the Tutorial Virtual machine (one subdirectory per chapter). There are also instructions for downloading the code in Catalyst::Manual::Tutorial::01_Intro. .PP For an excellent introduction to learning the many benefits of testing your Perl applications and modules, you might want to read 'Perl Testing: A Developer's Notebook' by Ian Langworth and chromatic. .ie n .SH "RUNNING THE ""CANNED"" CATALYST TESTS" .el .SH "RUNNING THE ``CANNED'' CATALYST TESTS" .IX Header "RUNNING THE CANNED CATALYST TESTS" There are a variety of ways to run Catalyst and Perl tests (for example, \&\f(CW\*(C`perl Makefile.PL\*(C'\fR and \f(CW\*(C`make test\*(C'\fR), but one of the easiest is with the \f(CW\*(C`prove\*(C'\fR command. For example, to run all of the tests in the \f(CW\*(C`t\*(C'\fR directory, enter: .PP .Vb 1 \& $ prove \-wl t .Ve .PP There will be a lot of output because we have the \f(CW\*(C`\-Debug\*(C'\fR flag enabled in \f(CW\*(C`lib/MyApp.pm\*(C'\fR (see the \f(CW\*(C`CATALYST_DEBUG=0\*(C'\fR tip below for a quick and easy way to reduce the clutter). Look for lines like this for errors: .PP .Vb 3 \& # Failed test \*(AqRequest should succeed\*(Aq \& # at t/controller_Books.t line 8. \& # Looks like you failed 1 test of 3. .Ve .PP The redirection used by the Authentication plugins will cause several failures in the default tests. You can fix this by making the following changes: .PP 1) Change the line in \f(CW\*(C`t/01app.t\*(C'\fR that reads: .PP .Vb 1 \& ok( request(\*(Aq/\*(Aq)\->is_success, \*(AqRequest should succeed\*(Aq ); .Ve .PP to: .PP .Vb 1 \& ok( request(\*(Aq/login\*(Aq)\->is_success, \*(AqRequest should succeed\*(Aq ); .Ve .PP 2) Change the line in \f(CW\*(C`t/controller_Logout.t\*(C'\fR that reads: .PP .Vb 1 \& ok( request(\*(Aq/logout\*(Aq)\->is_success, \*(AqRequest should succeed\*(Aq ); .Ve .PP to: .PP .Vb 1 \& ok( request(\*(Aq/logout\*(Aq)\->is_redirect, \*(AqRequest should succeed\*(Aq ); .Ve .PP 3) Change the line in \f(CW\*(C`t/controller_Books.t\*(C'\fR that reads: .PP .Vb 1 \& ok( request(\*(Aq/books\*(Aq)\->is_success, \*(AqRequest should succeed\*(Aq ); .Ve .PP to: .PP .Vb 1 \& ok( request(\*(Aq/books\*(Aq)\->is_redirect, \*(AqRequest should succeed\*(Aq ); .Ve .PP 4) Add the following statement to the top of \f(CW\*(C`t/view_HTML.t\*(C'\fR: .PP .Vb 1 \& use MyApp; .Ve .PP As you can see in the \f(CW\*(C`prove\*(C'\fR command line above, the \f(CW\*(C`\-l\*(C'\fR option (or \&\f(CW\*(C`\-\-lib\*(C'\fR if you prefer) is used to set the location of the Catalyst \&\f(CW\*(C`lib\*(C'\fR directory. With this command, you will get all of the usual development server debug output, something most people prefer to disable while running tests cases. Although you can edit the \f(CW\*(C`lib/MyApp.pm\*(C'\fR to comment out the \f(CW\*(C`\-Debug\*(C'\fR plugin, it's generally easier to simply set the \f(CW\*(C`CATALYST_DEBUG=0\*(C'\fR environment variable. For example: .PP .Vb 1 \& $ CATALYST_DEBUG=0 prove \-wl t .Ve .PP During the \f(CW\*(C`t/02pod\*(C'\fR and \f(CW\*(C`t/03podcoverage\*(C'\fR tests, you might notice the \&\f(CW\*(C`all skipped: set TEST_POD to enable this test\*(C'\fR warning message. To execute the Pod-related tests, add \f(CW\*(C`TEST_POD=1\*(C'\fR to the \f(CW\*(C`prove\*(C'\fR command: .PP .Vb 1 \& $ CATALYST_DEBUG=0 TEST_POD=1 prove \-wl t .Ve .PP If you omitted the Pod comments from any of the methods that were inserted, you might have to go back and fix them to get these tests to pass. :\-) .PP Another useful option is the \f(CW\*(C`verbose\*(C'\fR (\f(CW\*(C`\-v\*(C'\fR) option to \f(CW\*(C`prove\*(C'\fR. It prints the name of each test case as it is being run: .PP .Vb 1 \& $ CATALYST_DEBUG=0 prove \-vwl t .Ve .SH "RUNNING A SINGLE TEST" .IX Header "RUNNING A SINGLE TEST" You can also run a single script by appending its name to the \f(CW\*(C`prove\*(C'\fR command. For example: .PP .Vb 1 \& $ CATALYST_DEBUG=0 prove \-wl t/01app.t .Ve .PP Also note that you can also run tests directly from Perl without \&\f(CW\*(C`prove\*(C'\fR. For example: .PP .Vb 1 \& $ CATALYST_DEBUG=0 perl \-w \-Ilib t/01app.t .Ve .SH "ADDING YOUR OWN TEST SCRIPT" .IX Header "ADDING YOUR OWN TEST SCRIPT" Although the Catalyst helper scripts provide a basic level of checks \&\*(L"for free,\*(R" testing can become significantly more helpful when you write your own tests to exercise the various parts of your application. The Test::WWW::Mechanize::Catalyst module is very popular for writing these sorts of test cases. This module extends Test::WWW::Mechanize (and therefore WWW::Mechanize) to allow you to automate the action of a user \*(L"clicking around\*(R" inside your application. It gives you all the benefits of testing on a live system without the messiness of having to use an actual web server, and a real person to do the clicking. .PP To create a sample test case, open the \f(CW\*(C`t/live_app01.t\*(C'\fR file in your editor and enter the following: .PP .Vb 1 \& #!/usr/bin/env perl \& \& use strict; \& use warnings; \& use Test::More; \& \& # Need to specify the name of your app as arg on next line \& # Can also do: \& # use Test::WWW::Mechanize::Catalyst "MyApp"; \& \& BEGIN { use_ok("Test::WWW::Mechanize::Catalyst" => "MyApp") } \& \& # Create two \*(Aquser agents\*(Aq to simulate two different users (\*(Aqtest01\*(Aq & \*(Aqtest02\*(Aq) \& my $ua1 = Test::WWW::Mechanize::Catalyst\->new; \& my $ua2 = Test::WWW::Mechanize::Catalyst\->new; \& \& # Use a simplified for loop to do tests that are common to both users \& # Use get_ok() to make sure we can hit the base URL \& # Second arg = optional description of test (will be displayed for failed tests) \& # Note that in test scripts you send everything to \*(Aqhttp://localhost\*(Aq \& $_\->get_ok("http://localhost/", "Check redirect of base URL") for $ua1, $ua2; \& # Use title_is() to check the contents of the