📄 test.3
字号:
.Sp.Vb 10\& ok sub {\& open(OUT, ">x.dat") || die $!;\& print OUT "\ex{e000}";\& close OUT;\& my $bytecount = \-s \*(Aqx.dat\*(Aq;\& unlink \*(Aqx.dat\*(Aq or warn "Can\*(Aqt unlink : $!";\& return $bytecount;\& },\& 4\& ;.Ve.SpThe above test passes two values to \f(CW\*(C`ok(arg1, arg2)\*(C'\fR \*(-- the first a coderef, and the second is the number 4. Before \f(CW\*(C`ok\*(C'\fR compares them,it calls the coderef, and uses its return value as the real value ofthis parameter. Assuming that \f(CW$bytecount\fR returns 4, \f(CW\*(C`ok\*(C'\fR ends uptesting \f(CW\*(C`4 eq 4\*(C'\fR. Since that's true, this test passes..SpFinally, you can append an optional third argument, in\&\f(CW\*(C`ok(\f(CIarg1\f(CW,\f(CIarg2\f(CW, \f(CInote\f(CW)\*(C'\fR, where \fInote\fR is a string value thatwill be printed if the test fails. This should be some usefulinformation about the test, pertaining to why it failed, and/ora description of the test. For example:.Sp.Vb 4\& ok( grep($_ eq \*(Aqsomething unique\*(Aq, @stuff), 1,\& "Something that should be unique isn\*(Aqt!\en".\& \*(Aq@stuff = \*(Aq.join \*(Aq, \*(Aq, @stuff\& );.Ve.SpUnfortunately, a note cannot be used with the single argumentstyle of \f(CW\*(C`ok()\*(C'\fR. That is, if you try \f(CW\*(C`ok(\f(CIarg1\f(CW, \f(CInote\f(CW)\*(C'\fR, then\&\f(CW\*(C`Test\*(C'\fR will interpret this as \f(CW\*(C`ok(\f(CIarg1\f(CW, \f(CIarg2\f(CW)\*(C'\fR, and probablyend up testing \f(CW\*(C`\f(CIarg1\f(CW eq \f(CIarg2\f(CW\*(C'\fR \*(-- and that's not what you want!.SpAll of the above special cases can occasionally cause someproblems. See \*(L"\s-1BUGS\s0 and \s-1CAVEATS\s0\*(R"..ie n .IP """skip(\f(CIskip_if_true\f(CW, \f(CIargs...\f(CW)""" 4.el .IP "\f(CWskip(\f(CIskip_if_true\f(CW, \f(CIargs...\f(CW)\fR" 4.IX Item "skip(skip_if_true, args...)"This is used for tests that under some conditions can be skipped. It'sbasically equivalent to:.Sp.Vb 5\& if( $skip_if_true ) {\& ok(1);\& } else {\& ok( args... );\& }.Ve.Sp\&...except that the \f(CWok(1)\fR emits not just "\f(CW\*(C`ok \f(CItestnum\f(CW\*(C'\fR\*(L" butactually \*(R"\f(CW\*(C`ok \f(CItestnum\f(CW # \f(CIskip_if_true_value\f(CW\*(C'\fR"..SpThe arguments after the \fIskip_if_true\fR are what is fed to \f(CW\*(C`ok(...)\*(C'\fR ifthis test isn't skipped..SpExample usage:.Sp.Vb 2\& my $if_MSWin =\& $^O =~ m/MSWin/ ? \*(AqSkip if under MSWin\*(Aq : \*(Aq\*(Aq;\&\& # A test to be skipped if under MSWin (i.e., run except under MSWin)\& skip($if_MSWin, thing($foo), thing($bar) );.Ve.SpOr, going the other way:.Sp.Vb 2\& my $unless_MSWin =\& $^O =~ m/MSWin/ ? \*(Aq\*(Aq : \*(AqSkip unless under MSWin\*(Aq;\&\& # A test to be skipped unless under MSWin (i.e., run only under MSWin)\& skip($unless_MSWin, thing($foo), thing($bar) );.Ve.SpThe tricky thing to remember is that the first parameter is true ifyou want to \fIskip\fR the test, not \fIrun\fR it; and it also doubles as anote about why it's being skipped. So in the first codeblock above, readthe code as "skip if MSWin \*(-- (otherwise) test whether \f(CW\*(C`thing($foo)\*(C'\fR is\&\f(CW\*(C`thing($bar)\*(C'\fR\*(L" or for the second case, \*(R"skip unless MSWin..."..SpAlso, when your \fIskip_if_reason\fR string is true, it really should (forbackwards compatibility with older Test.pm versions) start with thestring \*(L"Skip\*(R", as shown in the above examples..SpNote that in the above cases, \f(CW\*(C`thing($foo)\*(C'\fR and \f(CW\*(C`thing($bar)\*(C'\fR\&\fIare\fR evaluated \*(-- but as long as the \f(CW\*(C`skip_if_true\*(C'\fR is true,then we \f(CW\*(C`skip(...)\*(C'\fR just tosses out their value (i.e., notbothering to treat them like values to \f(CW\*(C`ok(...)\*(C'\fR. But ifyou need to \fInot\fR eval the arguments when skipping thetest, usethis format:.Sp.Vb 7\& skip( $unless_MSWin,\& sub {\& # This code returns true if the test passes.\& # (But it doesn\*(Aqt even get called if the test is skipped.)\& thing($foo) eq thing($bar)\& }\& );.Ve.Spor even this, which is basically equivalent:.Sp.Vb 3\& skip( $unless_MSWin,\& sub { thing($foo) }, sub { thing($bar) }\& );.Ve.SpThat is, both are like this:.Sp.Vb 7\& if( $unless_MSWin ) {\& ok(1); # but it actually appends "# $unless_MSWin"\& # so that Test::Harness can tell it\*(Aqs a skip\& } else {\& # Not skipping, so actually call and evaluate...\& ok( sub { thing($foo) }, sub { thing($bar) } );\& }.Ve.SH "TEST TYPES".IX Header "TEST TYPES".IP "\(bu" 4\&\s-1NORMAL\s0 \s-1TESTS\s0.SpThese tests are expected to succeed. Usually, most or all of your testsare in this category. If a normal test doesn't succeed, then thatmeans that something is \fIwrong\fR..IP "\(bu" 4\&\s-1SKIPPED\s0 \s-1TESTS\s0.SpThe \f(CW\*(C`skip(...)\*(C'\fR function is for tests that might or might not bepossible to run, dependingon the availability of platform-specific features. The first argumentshould evaluate to true (think \*(L"yes, please skip\*(R") if the requiredfeature is \fInot\fR available. After the first argument, \f(CW\*(C`skip(...)\*(C'\fR worksexactly the same way as \f(CW\*(C`ok(...)\*(C'\fR does..IP "\(bu" 4\&\s-1TODO\s0 \s-1TESTS\s0.Sp\&\s-1TODO\s0 tests are designed for maintaining an \fBexecutable \s-1TODO\s0 list\fR.These tests are \fIexpected to fail.\fR If a \s-1TODO\s0 test does succeed,then the feature in question shouldn't be on the \s-1TODO\s0 list, nowshould it?.SpPackages should \s-1NOT\s0 be released with succeeding \s-1TODO\s0 tests. As soonas a \s-1TODO\s0 test starts working, it should be promoted to a normal test,and the newly working feature should be documented in the releasenotes or in the change log..SH "ONFAIL".IX Header "ONFAIL".Vb 1\& BEGIN { plan test => 4, onfail => sub { warn "CALL 911!" } }.Ve.PPAlthough test failures should be enough, extra diagnostics can betriggered at the end of a test run. \f(CW\*(C`onfail\*(C'\fR is passed an array refof hash refs that describe each test failure. Each hash will containat least the following fields: \f(CW\*(C`package\*(C'\fR, \f(CW\*(C`repetition\*(C'\fR, and\&\f(CW\*(C`result\*(C'\fR. (You shouldn't rely on any other fields being present.) If the testhad an expected value or a diagnostic (or \*(L"note\*(R") string, these will also beincluded..PPThe \fIoptional\fR \f(CW\*(C`onfail\*(C'\fR hook might be used simply to print out theversion of your package and/or how to report problems. It might alsobe used to generate extremely sophisticated diagnostics for aparticularly bizarre test failure. However it's not a panacea. Coredumps or other unrecoverable errors prevent the \f(CW\*(C`onfail\*(C'\fR hook fromrunning. (It is run inside an \f(CW\*(C`END\*(C'\fR block.) Besides, \f(CW\*(C`onfail\*(C'\fR isprobably over-kill in most cases. (Your test code should be simplerthan the code it is testing, yes?).SH "BUGS and CAVEATS".IX Header "BUGS and CAVEATS".IP "\(bu" 4\&\f(CW\*(C`ok(...)\*(C'\fR's special handing of strings which look like they might beregexes can also cause unexpected behavior. An innocent:.Sp.Vb 1\& ok( $fileglob, \*(Aq/path/to/some/*stuff/\*(Aq );.Ve.Spwill fail, since Test.pm considers the second argument to be a regex!The best bet is to use the one-argument form:.Sp.Vb 1\& ok( $fileglob eq \*(Aq/path/to/some/*stuff/\*(Aq );.Ve.IP "\(bu" 4\&\f(CW\*(C`ok(...)\*(C'\fR's use of string \f(CW\*(C`eq\*(C'\fR can sometimes cause odd problemswhen comparingnumbers, especially if you're casting a string to a number:.Sp.Vb 2\& $foo = "1.0";\& ok( $foo, 1 ); # not ok, "1.0" ne 1.Ve.SpYour best bet is to use the single argument form:.Sp.Vb 1\& ok( $foo == 1 ); # ok "1.0" == 1.Ve.IP "\(bu" 4As you may have inferred from the above documentation and examples,\&\f(CW\*(C`ok\*(C'\fR's prototype is \f(CW\*(C`($;$$)\*(C'\fR (and, incidentally, \f(CW\*(C`skip\*(C'\fR's is\&\f(CW\*(C`($;$$$)\*(C'\fR). This means, for example, that you can do \f(CW\*(C`ok @foo, @bar\*(C'\fRto compare the \fIsize\fR of the two arrays. But don't be fooled intothinking that \f(CW\*(C`ok @foo, @bar\*(C'\fR means a comparison of the contents of twoarrays \*(-- you're comparing \fIjust\fR the number of elements of each. It'sso easy to make that mistake in reading \f(CW\*(C`ok @foo, @bar\*(C'\fR that you mightwant to be very explicit about it, and instead write \f(CW\*(C`ok scalar(@foo),scalar(@bar)\*(C'\fR..IP "\(bu" 4This almost definitely doesn't do what you expect:.Sp.Vb 1\& ok $thingy\->can(\*(Aqsome_method\*(Aq);.Ve.SpWhy? Because \f(CW\*(C`can\*(C'\fR returns a coderef to mean \*(L"yes it can (and themethod is this...)\*(R", and then \f(CW\*(C`ok\*(C'\fR sees a coderef and thinks you'repassing a function that you want it to call and consider the truth ofthe result of! I.e., just like:.Sp.Vb 1\& ok $thingy\->can(\*(Aqsome_method\*(Aq)\->();.Ve.SpWhat you probably want instead is this:.Sp.Vb 1\& ok $thingy\->can(\*(Aqsome_method\*(Aq) && 1;.Ve.SpIf the \f(CW\*(C`can\*(C'\fR returns false, then that is passed to \f(CW\*(C`ok\*(C'\fR. If itreturns true, then the larger expression \f(CW\*(C`$thingy\->can(\*(Aqsome_method\*(Aq)\ &&\ 1\*(C'\fR returns 1, which \f(CW\*(C`ok\*(C'\fR sees asa simple signal of success, as you would expect..IP "\(bu" 4The syntax for \f(CW\*(C`skip\*(C'\fR is about the only way it can be, but it's stillquite confusing. Just start with the above examples and you'llbe okay..SpMoreover, users may expect this:.Sp.Vb 1\& skip $unless_mswin, foo($bar), baz($quux);.Ve.Spto not evaluate \f(CW\*(C`foo($bar)\*(C'\fR and \f(CW\*(C`baz($quux)\*(C'\fR when the test is beingskipped. But in reality, they \fIare\fR evaluated, but \f(CW\*(C`skip\*(C'\fR just won'tbother comparing them if \f(CW$unless_mswin\fR is true..SpYou could do this:.Sp.Vb 1\& skip $unless_mswin, sub{foo($bar)}, sub{baz($quux)};.Ve.SpBut that's not terribly pretty. You may find it simpler or clearer inthe long run to just do things like this:.Sp.Vb 10\& if( $^O =~ m/MSWin/ ) {\& print "# Yay, we\*(Aqre under $^O\en";\& ok foo($bar), baz($quux);\& ok thing($whatever), baz($stuff);\& ok blorp($quux, $whatever);\& ok foo($barzbarz), thang($quux);\& } else {\& print "# Feh, we\*(Aqre under $^O. Watch me skip some tests...\en";\& for(1 .. 4) { skip "Skip unless under MSWin" }\& }.Ve.SpBut be quite sure that \f(CW\*(C`ok\*(C'\fR is called exactly as many times in thefirst block as \f(CW\*(C`skip\*(C'\fR is called in the second block..SH "ENVIRONMENT".IX Header "ENVIRONMENT"If \f(CW\*(C`PERL_TEST_DIFF\*(C'\fR environment variable is set, it will be used as acommand for comparing unexpected multiline results. If you have \s-1GNU\s0diff installed, you might want to set \f(CW\*(C`PERL_TEST_DIFF\*(C'\fR to \f(CW\*(C`diff \-u\*(C'\fR.If you don't have a suitable program, you might install the\&\f(CW\*(C`Text::Diff\*(C'\fR module and then set \f(CW\*(C`PERL_TEST_DIFF\*(C'\fR to be \f(CW\*(C`perl\&\-MText::Diff \-e \*(Aqprint diff(@ARGV)\*(Aq\*(C'\fR. If \f(CW\*(C`PERL_TEST_DIFF\*(C'\fR isn't setbut the \f(CW\*(C`Algorithm::Diff\*(C'\fR module is available, then it will be usedto show the differences in multiline results..SH "NOTE".IX Header "NOTE"A past developer of this module once said that it was no longer beingactively developed. However, rumors of its demise were greatlyexaggerated. Feedback and suggestions are quite welcome..PPBe aware that the main value of this module is its simplicity. Notethat there are already more ambitious modules out there, such asTest::More and Test::Unit..PPSome earlier versions of this module had docs with some confusingtypos in the description of \f(CW\*(C`skip(...)\*(C'\fR..SH "SEE ALSO".IX Header "SEE ALSO"Test::Harness.PPTest::Simple, Test::More, Devel::Cover.PPTest::Builder for building your own testing library..PPTest::Unit is an interesting XUnit-style testing library..PPTest::Inline and SelfTest let you embed tests in code..SH "AUTHOR".IX Header "AUTHOR"Copyright (c) 1998\-2000 Joshua Nathaniel Pritikin. All rights reserved..PPCopyright (c) 2001\-2002 Michael G. Schwern..PPCopyright (c) 2002\-2004 and counting Sean M. Burke..PPCurrent maintainer: Sean M. Burke. <sburke@cpan.org>.PPThis package is free software and is provided \*(L"as is\*(R" without expressor implied warranty. It may be used, redistributed and/or modifiedunder the same terms as Perl itself.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -