📄 more.pm
字号:
URI::Geller->bend_spoon; is( $spoon, 'bent', "Spoon bending, that's original" ); }With a todo block, the tests inside are expected to fail. Test::Morewill run the tests normally, but print out special flags indicatingthey are "todo". Test::Harness will interpret failures as being ok.Should anything succeed, it will report it as an unexpected success.You then know the thing you had todo is done and can remove theTODO flag.The nice part about todo tests, as opposed to simply commenting out ablock of tests, is it's like having a programmatic todo list. You knowhow much work is left to be done, you're aware of what bugs there are,and you'll know immediately when they're fixed.Once a todo test starts succeeding, simply move it outside the block.When the block is empty, delete it.=item B<todo_skip> TODO: { todo_skip $why, $how_many if $condition; ...normal testing code... }With todo tests, it's best to have the tests actually run. That wayyou'll know when they start passing. Sometimes this isn't possible.Often a failing test will cause the whole program to die or hang, eveninside an C<eval BLOCK> with and using C<alarm>. In these extremecases you have no choice but to skip over the broken tests entirely.The syntax and behavior is similar to a C<SKIP: BLOCK> except thetests will be marked as failing but todo. Test::Harness willinterpret them as passing.=cutsub todo_skip { my($why, $how_many) = @_; unless( defined $how_many ) { # $how_many can only be avoided when no_plan is in use. _carp "todo_skip() needs to know \$how_many tests are in the block" unless $Test::Builder::No_Plan; $how_many = 1; } for( 1..$how_many ) { $Test->todo_skip($why); } local $^W = 0; last TODO;}=item When do I use SKIP vs. TODO?B<If it's something the user might not be able to do>, use SKIP.This includes optional modules that aren't installed, running underan OS that doesn't have some feature (like fork() or symlinks), or maybeyou need an Internet connection and one isn't available.B<If it's something the programmer hasn't done yet>, use TODO. Thisis for any code you haven't written yet, or bugs you have yet to fix,but want to put tests in your testing script (always a good idea).=back=head2 Comparison functionsNot everything is a simple eq check or regex. There are times youneed to see if two arrays are equivalent, for instance. For theseinstances, Test::More provides a handful of useful functions.B<NOTE> These are NOT well-tested on circular references. Nor am Iquite sure what will happen with filehandles.=over 4=item B<is_deeply> is_deeply( $this, $that, $test_name );Similar to is(), except that if $this and $that are hash or arrayreferences, it does a deep comparison walking each data structure tosee if they are equivalent. If the two structures are different, itwill display the place where they start differing.Barrie Slaymaker's Test::Differences module provides more in-depthfunctionality along these lines, and it plays well with Test::More.B<NOTE> Display of scalar refs is not quite 100%=cutuse vars qw(@Data_Stack);my $DNE = bless [], 'Does::Not::Exist';sub is_deeply { my($this, $that, $name) = @_; my $ok; if( !ref $this || !ref $that ) { $ok = $Test->is_eq($this, $that, $name); } else { local @Data_Stack = (); if( _deep_check($this, $that) ) { $ok = $Test->ok(1, $name); } else { $ok = $Test->ok(0, $name); $ok = $Test->diag(_format_stack(@Data_Stack)); } } return $ok;}sub _format_stack { my(@Stack) = @_; my $var = '$FOO'; my $did_arrow = 0; foreach my $entry (@Stack) { my $type = $entry->{type} || ''; my $idx = $entry->{'idx'}; if( $type eq 'HASH' ) { $var .= "->" unless $did_arrow++; $var .= "{$idx}"; } elsif( $type eq 'ARRAY' ) { $var .= "->" unless $did_arrow++; $var .= "[$idx]"; } elsif( $type eq 'REF' ) { $var = "\${$var}"; } } my @vals = @{$Stack[-1]{vals}}[0,1]; my @vars = (); ($vars[0] = $var) =~ s/\$FOO/ \$got/; ($vars[1] = $var) =~ s/\$FOO/\$expected/; my $out = "Structures begin differing at:\n"; foreach my $idx (0..$#vals) { my $val = $vals[$idx]; $vals[$idx] = !defined $val ? 'undef' : $val eq $DNE ? "Does not exist" : "'$val'"; } $out .= "$vars[0] = $vals[0]\n"; $out .= "$vars[1] = $vals[1]\n"; $out =~ s/^/ /msg; return $out;}=item B<eq_array> eq_array(\@this, \@that);Checks if two arrays are equivalent. This is a deep check, somulti-level structures are handled correctly.=cut#'#sub eq_array { my($a1, $a2) = @_; return 1 if $a1 eq $a2; my $ok = 1; my $max = $#$a1 > $#$a2 ? $#$a1 : $#$a2; for (0..$max) { my $e1 = $_ > $#$a1 ? $DNE : $a1->[$_]; my $e2 = $_ > $#$a2 ? $DNE : $a2->[$_]; push @Data_Stack, { type => 'ARRAY', idx => $_, vals => [$e1, $e2] }; $ok = _deep_check($e1,$e2); pop @Data_Stack if $ok; last unless $ok; } return $ok;}sub _deep_check { my($e1, $e2) = @_; my $ok = 0; my $eq; { # Quiet uninitialized value warnings when comparing undefs. local $^W = 0; if( $e1 eq $e2 ) { $ok = 1; } else { if( UNIVERSAL::isa($e1, 'ARRAY') and UNIVERSAL::isa($e2, 'ARRAY') ) { $ok = eq_array($e1, $e2); } elsif( UNIVERSAL::isa($e1, 'HASH') and UNIVERSAL::isa($e2, 'HASH') ) { $ok = eq_hash($e1, $e2); } elsif( UNIVERSAL::isa($e1, 'REF') and UNIVERSAL::isa($e2, 'REF') ) { push @Data_Stack, { type => 'REF', vals => [$e1, $e2] }; $ok = _deep_check($$e1, $$e2); pop @Data_Stack if $ok; } elsif( UNIVERSAL::isa($e1, 'SCALAR') and UNIVERSAL::isa($e2, 'SCALAR') ) { push @Data_Stack, { type => 'REF', vals => [$e1, $e2] }; $ok = _deep_check($$e1, $$e2); } else { push @Data_Stack, { vals => [$e1, $e2] }; $ok = 0; } } } return $ok;}=item B<eq_hash> eq_hash(\%this, \%that);Determines if the two hashes contain the same keys and values. Thisis a deep check.=cutsub eq_hash { my($a1, $a2) = @_; return 1 if $a1 eq $a2; my $ok = 1; my $bigger = keys %$a1 > keys %$a2 ? $a1 : $a2; foreach my $k (keys %$bigger) { my $e1 = exists $a1->{$k} ? $a1->{$k} : $DNE; my $e2 = exists $a2->{$k} ? $a2->{$k} : $DNE; push @Data_Stack, { type => 'HASH', idx => $k, vals => [$e1, $e2] }; $ok = _deep_check($e1, $e2); pop @Data_Stack if $ok; last unless $ok; } return $ok;}=item B<eq_set> eq_set(\@this, \@that);Similar to eq_array(), except the order of the elements is B<not>important. This is a deep check, but the irrelevancy of order onlyapplies to the top level.B<NOTE> By historical accident, this is not a true set comparision.While the order of elements does not matter, duplicate elements do.=cut# We must make sure that references are treated neutrally. It really# doesn't matter how we sort them, as long as both arrays are sorted# with the same algorithm.sub _bogus_sort { local $^W = 0; ref $a ? 0 : $a cmp $b }sub eq_set { my($a1, $a2) = @_; return 0 unless @$a1 == @$a2; # There's faster ways to do this, but this is easiest. return eq_array( [sort _bogus_sort @$a1], [sort _bogus_sort @$a2] );}=back=head2 Extending and Embedding Test::MoreSometimes the Test::More interface isn't quite enough. Fortunately,Test::More is built on top of Test::Builder which provides a single,unified backend for any test library to use. This means two testlibraries which both use Test::Builder B<can be used together in thesame program>.If you simply want to do a little tweaking of how the tests behave,you can access the underlying Test::Builder object like so:=over 4=item B<builder> my $test_builder = Test::More->builder;Returns the Test::Builder object underlying Test::More for you to playwith.=cutsub builder { return Test::Builder->new;}=back=head1 NOTESTest::More is B<explicitly> tested all the way back to perl 5.004.Test::More is thread-safe for perl 5.8.0 and up.=head1 BUGS and CAVEATS=over 4=item Making your own ok()If you are trying to extend Test::More, don't. Use Test::Builderinstead.=item The eq_* family has some caveats.=item Test::Harness upgradesno_plan and todo depend on new Test::Harness features and fixes. Ifyou're going to distribute tests that use no_plan or todo yourend-users will have to upgrade Test::Harness to the latest one onCPAN. If you avoid no_plan and TODO tests, the stock Test::Harnesswill work fine.If you simply depend on Test::More, it's own dependencies will cause aTest::Harness upgrade.=back=head1 HISTORYThis is a case of convergent evolution with Joshua Pritikin's Testmodule. I was largely unaware of its existence when I'd firstwritten my own ok() routines. This module exists because I can'tfigure out how to easily wedge test names into Test's interface (alongwith a few other problems).The goal here is to have a testing utility that's simple to learn,quick to use and difficult to trip yourself up with while stillproviding more flexibility than the existing Test.pm. As such, thenames of the most common routines are kept tiny, special cases andmagic side-effects are kept to a minimum. WYSIWYG.=head1 SEE ALSOL<Test::Simple> if all this confuses you and you just want to writesome tests. You can upgrade to Test::More later (it's forwardcompatible).L<Test::Differences> for more ways to test complex data structures.And it plays well with Test::More.L<Test> is the old testing module. Its main benefit is that it hasbeen distributed with Perl since 5.004_05.L<Test::Harness> for details on how your test results are interpretedby Perl.L<Test::Unit> describes a very featureful unit testing interface.L<Test::Inline> shows the idea of embedded testing.L<SelfTest> is another approach to embedded testing.=head1 AUTHORSMichael G Schwern E<lt>schwern@pobox.comE<gt> with much inspirationfrom Joshua Pritikin's Test module and lots of help from BarrieSlaymaker, Tony Bowden, chromatic and the perl-qa gang.=head1 COPYRIGHTCopyright 2001 by Michael G Schwern E<lt>schwern@pobox.comE<gt>.This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.See F<http://www.perl.com/perl/misc/Artistic.html>=cut1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -