📄 test::tutorial.3
字号:
\& not ok 6 \- day()\& # Failed test (\- at line 16)\& # got: \*(Aq16\*(Aq\& # expected: \*(Aq17\*(Aq\& ok 7 \- month()\& ok 8 \- year()\& # Looks like you failed 1 tests of 8..Ve.PPletting us know that \f(CW\*(C`$ical\->day\*(C'\fR returned 16, but we expected 17. Aquick check shows that the code is working fine, we made a mistakewhen writing up the tests. Just change it to:.PP.Vb 1\& is( $ical\->day, 16, \*(Aq day()\*(Aq );.Ve.PPand everything works..PPSo any time you're doing a \*(L"this equals that\*(R" sort of test, use \f(CW\*(C`is()\*(C'\fR.It even works on arrays. The test is always in scalar context, so youcan test how many elements are in a list this way. [5].PP.Vb 1\& is( @foo, 5, \*(Aqfoo has 5 elements\*(Aq );.Ve.Sh "Sometimes the tests are wrong".IX Subsection "Sometimes the tests are wrong"Which brings us to a very important lesson. Code has bugs. Tests arecode. Ergo, tests have bugs. A failing test could mean a bug in thecode, but don't discount the possibility that the test is wrong..PPOn the flip side, don't be tempted to prematurely declare a testincorrect just because you're having trouble finding the bug.Invalidating a test isn't something to be taken lightly, and don't useit as a cop out to avoid work..Sh "Testing lots of values".IX Subsection "Testing lots of values"We're going to be wanting to test a lot of dates here, trying to trickthe code with lots of different edge cases. Does it work before 1970?After 2038? Before 1904? Do years after 10,000 give it trouble?Does it get leap years right? We could keep repeating the code above,or we could set up a little try/expect loop..PP.Vb 2\& use Test::More tests => 32;\& use Date::ICal;\&\& my %ICal_Dates = (\& # An ICal string And the year, month, date\& # hour, minute and second we expect.\& \*(Aq19971024T120000\*(Aq => # from the docs.\& [ 1997, 10, 24, 12, 0, 0 ],\& \*(Aq20390123T232832\*(Aq => # after the Unix epoch\& [ 2039, 1, 23, 23, 28, 32 ],\& \*(Aq19671225T000000\*(Aq => # before the Unix epoch\& [ 1967, 12, 25, 0, 0, 0 ],\& \*(Aq18990505T232323\*(Aq => # before the MacOS epoch\& [ 1899, 5, 5, 23, 23, 23 ],\& );\&\&\& while( my($ical_str, $expect) = each %ICal_Dates ) {\& my $ical = Date::ICal\->new( ical => $ical_str );\&\& ok( defined $ical, "new(ical => \*(Aq$ical_str\*(Aq)" );\& ok( $ical\->isa(\*(AqDate::ICal\*(Aq), " and it\*(Aqs the right class" );\&\& is( $ical\->year, $expect\->[0], \*(Aq year()\*(Aq );\& is( $ical\->month, $expect\->[1], \*(Aq month()\*(Aq );\& is( $ical\->day, $expect\->[2], \*(Aq day()\*(Aq );\& is( $ical\->hour, $expect\->[3], \*(Aq hour()\*(Aq );\& is( $ical\->min, $expect\->[4], \*(Aq min()\*(Aq ); \& is( $ical\->sec, $expect\->[5], \*(Aq sec()\*(Aq );\& }.Ve.PPSo now we can test bunches of dates by just adding them to\&\f(CW%ICal_Dates\fR. Now that it's less work to test with more dates, you'llbe inclined to just throw more in as you think of them.Only problem is, every time we add to that we have to keep adjustingthe \f(CW\*(C`use Test::More tests => ##\*(C'\fR line. That can rapidly getannoying. There's two ways to make this work better..PPFirst, we can calculate the plan dynamically using the \f(CW\*(C`plan()\*(C'\fRfunction..PP.Vb 2\& use Test::More;\& use Date::ICal;\&\& my %ICal_Dates = (\& ...same as before...\& );\&\& # For each key in the hash we\*(Aqre running 8 tests.\& plan tests => keys %ICal_Dates * 8;.Ve.PPOr to be even more flexible, we use \f(CW\*(C`no_plan\*(C'\fR. This means we're justrunning some tests, don't know how many. [6].PP.Vb 1\& use Test::More \*(Aqno_plan\*(Aq; # instead of tests => 32.Ve.PPnow we can just add tests and not have to do all sorts of math tofigure out how many we're running..Sh "Informative names".IX Subsection "Informative names"Take a look at this line here.PP.Vb 1\& ok( defined $ical, "new(ical => \*(Aq$ical_str\*(Aq)" );.Ve.PPwe've added more detail about what we're testing and the ICal stringitself we're trying out to the name. So you get results like:.PP.Vb 8\& ok 25 \- new(ical => \*(Aq19971024T120000\*(Aq)\& ok 26 \- and it\*(Aqs the right class\& ok 27 \- year()\& ok 28 \- month()\& ok 29 \- day()\& ok 30 \- hour()\& ok 31 \- min()\& ok 32 \- sec().Ve.PPif something in there fails, you'll know which one it was and thatwill make tracking down the problem easier. So try to put a bit ofdebugging information into the test names..PPDescribe what the tests test, to make debugging a failed test easierfor you or for the next person who runs your test..Sh "Skipping tests".IX Subsection "Skipping tests"Poking around in the existing Date::ICal tests, I found this in\&\fIt/01sanity.t\fR [7].PP.Vb 1\& #!/usr/bin/perl \-w\&\& use Test::More tests => 7;\& use Date::ICal;\&\& # Make sure epoch time is being handled sanely.\& my $t1 = Date::ICal\->new( epoch => 0 );\& is( $t1\->epoch, 0, "Epoch time of 0" );\&\& # XXX This will only work on unix systems.\& is( $t1\->ical, \*(Aq19700101Z\*(Aq, " epoch to ical" );\&\& is( $t1\->year, 1970, " year()" );\& is( $t1\->month, 1, " month()" );\& is( $t1\->day, 1, " day()" );\&\& # like the tests above, but starting with ical instead of epoch\& my $t2 = Date::ICal\->new( ical => \*(Aq19700101Z\*(Aq );\& is( $t2\->ical, \*(Aq19700101Z\*(Aq, "Start of epoch in ICal notation" );\&\& is( $t2\->epoch, 0, " and back to ICal" );.Ve.PPThe beginning of the epoch is different on most non-Unix operatingsystems [8]. Even though Perl smooths out the differences for the mostpart, certain ports do it differently. MacPerl is one off the top ofmy head. [9] We \fIknow\fR this will never work on MacOS. So rather thanjust putting a comment in the test, we can explicitly say it's nevergoing to work and skip the test..PP.Vb 2\& use Test::More tests => 7;\& use Date::ICal;\&\& # Make sure epoch time is being handled sanely.\& my $t1 = Date::ICal\->new( epoch => 0 );\& is( $t1\->epoch, 0, "Epoch time of 0" );\&\& SKIP: {\& skip(\*(Aqepoch to ICal not working on MacOS\*(Aq, 6) \& if $^O eq \*(AqMacOS\*(Aq;\&\& is( $t1\->ical, \*(Aq19700101Z\*(Aq, " epoch to ical" );\&\& is( $t1\->year, 1970, " year()" );\& is( $t1\->month, 1, " month()" );\& is( $t1\->day, 1, " day()" );\&\& # like the tests above, but starting with ical instead of epoch\& my $t2 = Date::ICal\->new( ical => \*(Aq19700101Z\*(Aq );\& is( $t2\->ical, \*(Aq19700101Z\*(Aq, "Start of epoch in ICal notation" );\&\& is( $t2\->epoch, 0, " and back to ICal" );\& }.Ve.PPA little bit of magic happens here. When running on anything butMacOS, all the tests run normally. But when on MacOS, \f(CW\*(C`skip()\*(C'\fR causesthe entire contents of the \s-1SKIP\s0 block to be jumped over. It's neverrun. Instead, it prints special output that tells Test::Harness thatthe tests have been skipped..PP.Vb 8\& 1..7\& ok 1 \- Epoch time of 0\& ok 2 # skip epoch to ICal not working on MacOS\& ok 3 # skip epoch to ICal not working on MacOS\& ok 4 # skip epoch to ICal not working on MacOS\& ok 5 # skip epoch to ICal not working on MacOS\& ok 6 # skip epoch to ICal not working on MacOS\& ok 7 # skip epoch to ICal not working on MacOS.Ve.PPThis means your tests won't fail on MacOS. This means less emailsfrom MacPerl users telling you about failing tests that you know willnever work. You've got to be careful with skip tests. These are fortests which don't work and \fInever will\fR. It is not for skippinggenuine bugs (we'll get to that in a moment)..PPThe tests are wholly and completely skipped. [10] This will work..PP.Vb 2\& SKIP: {\& skip("I don\*(Aqt wanna die!");\&\& die, die, die, die, die;\& }.Ve.Sh "Todo tests".IX Subsection "Todo tests"Thumbing through the Date::ICal man page, I came across this:.PP.Vb 1\& ical\&\& $ical_string = $ical\->ical;\&\& Retrieves, or sets, the date on the object, using any\& valid ICal date/time string..Ve.PP\&\*(L"Retrieves or sets\*(R". Hmmm, didn't see a test for using \f(CW\*(C`ical()\*(C'\fR to setthe date in the Date::ICal test suite. So I'll write one..PP.Vb 2\& use Test::More tests => 1;\& use Date::ICal;\&\& my $ical = Date::ICal\->new;\& $ical\->ical(\*(Aq20201231Z\*(Aq);\& is( $ical\->ical, \*(Aq20201231Z\*(Aq, \*(AqSetting via ical()\*(Aq );.Ve.PPrun that and I get.PP.Vb 6\& 1..1\& not ok 1 \- Setting via ical()\& # Failed test (\- at line 6)\& # got: \*(Aq20010814T233649Z\*(Aq\& # expected: \*(Aq20201231Z\*(Aq\& # Looks like you failed 1 tests of 1..Ve.PPWhoops! Looks like it's unimplemented. Let's assume we don't havethe time to fix this. [11] Normally, you'd just comment out the testand put a note in a todo list somewhere. Instead, we're going toexplicitly state \*(L"this test will fail\*(R" by wrapping it in a \f(CW\*(C`TODO\*(C'\fR block..PP.Vb 1\& use Test::More tests => 1;\&\& TODO: {\& local $TODO = \*(Aqical($ical) not yet implemented\*(Aq;\&\& my $ical = Date::ICal\->new;\& $ical\->ical(\*(Aq20201231Z\*(Aq);\&\& is( $ical\->ical, \*(Aq20201231Z\*(Aq, \*(AqSetting via ical()\*(Aq );\& }.Ve.PPNow when you run, it's a little different:.PP.Vb 4\& 1..1\& not ok 1 \- Setting via ical() # TODO ical($ical) not yet implemented\& # got: \*(Aq20010822T201551Z\*(Aq\& # expected: \*(Aq20201231Z\*(Aq.Ve.PPTest::More doesn't say \*(L"Looks like you failed 1 tests of 1\*(R". That '#\&\s-1TODO\s0' tells Test::Harness \*(L"this is supposed to fail\*(R" and it treats afailure as a successful test. So you can write tests even beforeyou've fixed the underlying code..PPIf a \s-1TODO\s0 test passes, Test::Harness will report it \*(L"\s-1UNEXPECTEDLY\s0\&\s-1SUCCEEDED\s0\*(R". When that happens, you simply remove the \s-1TODO\s0 block with\&\f(CW\*(C`local $TODO\*(C'\fR and turn it into a real test..Sh "Testing with taint mode.".IX Subsection "Testing with taint mode."Taint mode is a funny thing. It's the globalest of all globalfeatures. Once you turn it on, it affects \fIall\fR code in your programand \fIall\fR modules used (and all the modules they use). If a singlepiece of code isn't taint clean, the whole thing explodes. With thatin mind, it's very important to ensure your module works under taintmode..PPIt's very simple to have your tests run under taint mode. Just throwa \f(CW\*(C`\-T\*(C'\fR into the \f(CW\*(C`#!\*(C'\fR line. Test::Harness will read the switchesin \f(CW\*(C`#!\*(C'\fR and use them to run your tests..PP.Vb 1\& #!/usr/bin/perl \-Tw\&\& ...test normally here....Ve.PPSo when you say \f(CW\*(C`make test\*(C'\fR it will be run with taint mode andwarnings on..SH "FOOTNOTES".IX Header "FOOTNOTES".IP "1." 4The first number doesn't really mean anything, but it has to be 1.It's the second number that's important..IP "2." 4For those following along at home, I'm using version 1.31. It hassome bugs, which is good \*(-- we'll uncover them with our tests..IP "3." 4You can actually take this one step further and test the manualitself. Have a look at \fBTest::Inline\fR (formerly \fBPod::Tests\fR)..IP "4." 4Yes, there's a mistake in the test suite. What! Me, contrived?.IP "5." 4We'll get to testing the contents of lists later..IP "6." 4But what happens if your test program dies halfway through?! Since wedidn't say how many tests we're going to run, how can we know itfailed? No problem, Test::More employs some magic to catch that deathand turn the test into a failure, even if every test passed up to thatpoint..IP "7." 4I cleaned it up a little..IP "8." 4Most Operating Systems record time as the number of seconds since acertain date. This date is the beginning of the epoch. Unix's startsat midnight January 1st, 1970 \s-1GMT\s0..IP "9." 4MacOS's epoch is midnight January 1st, 1904. \s-1VMS\s0's is midnight,November 17th, 1858, but vmsperl emulates the Unix epoch so it's not aproblem..IP "10." 4As long as the code inside the \s-1SKIP\s0 block at least compiles. Pleasedon't ask how. No, it's not a filter..IP "11." 4Do \s-1NOT\s0 be tempted to use \s-1TODO\s0 tests as a way to avoid fixing simplebugs!.SH "AUTHORS".IX Header "AUTHORS"Michael G Schwern <schwern@pobox.com> and the perl-qa dancers!.SH "COPYRIGHT".IX Header "COPYRIGHT"Copyright 2001 by Michael G Schwern <schwern@pobox.com>..PPThis documentation is free; you can redistribute it and/or modify itunder the same terms as Perl itself..PPIrrespective of its distribution, all code examples in these filesare hereby placed into the public domain. You are permitted andencouraged to use this code in your own programs for funor for profit as you see fit. A simple comment in the code givingcredit would be courteous but is not required.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -