📄 more.pm
字号:
(for example 'Test customer').=cutsub isa_ok ($$;$) { my($object, $class, $obj_name) = @_; my $tb = Test::More->builder; my $diag; $obj_name = 'The object' unless defined $obj_name; my $name = "$obj_name isa $class"; if( !defined $object ) { $diag = "$obj_name isn't defined"; } elsif( !ref $object ) { $diag = "$obj_name isn't a reference"; } else { # We can't use UNIVERSAL::isa because we want to honor isa() overrides my($rslt, $error) = $tb->_try(sub { $object->isa($class) }); if( $error ) { if( $error =~ /^Can't call method "isa" on unblessed reference/ ) { # Its an unblessed reference if( !UNIVERSAL::isa($object, $class) ) { my $ref = ref $object; $diag = "$obj_name isn't a '$class' it's a '$ref'"; } } else { die <<WHOA;WHOA! I tried to call ->isa on your object and got some weird error.Here's the error.$errorWHOA } } elsif( !$rslt ) { my $ref = ref $object; $diag = "$obj_name isn't a '$class' it's a '$ref'"; } } my $ok; if( $diag ) { $ok = $tb->ok( 0, $name ); $tb->diag(" $diag\n"); } else { $ok = $tb->ok( 1, $name ); } return $ok;}=item B<pass>=item B<fail> pass($test_name); fail($test_name);Sometimes you just want to say that the tests have passed. Usuallythe case is you've got some complicated condition that is difficult towedge into an ok(). In this case, you can simply use pass() (todeclare the test ok) or fail (for not ok). They are synonyms forok(1) and ok(0).Use these very, very, very sparingly.=cutsub pass (;$) { my $tb = Test::More->builder; $tb->ok(1, @_);}sub fail (;$) { my $tb = Test::More->builder; $tb->ok(0, @_);}=back=head2 Module testsYou usually want to test if the module you're testing loads ok, ratherthan just vomiting if its load fails. For such purposes we haveC<use_ok> and C<require_ok>.=over 4=item B<use_ok> BEGIN { use_ok($module); } BEGIN { use_ok($module, @imports); }These simply use the given $module and test to make sure the loadhappened ok. It's recommended that you run use_ok() inside a BEGINblock so its functions are exported at compile-time and prototypes areproperly honored.If @imports are given, they are passed through to the use. So this: BEGIN { use_ok('Some::Module', qw(foo bar)) }is like doing this: use Some::Module qw(foo bar);Version numbers can be checked like so: # Just like "use Some::Module 1.02" BEGIN { use_ok('Some::Module', 1.02) }Don't try to do this: BEGIN { use_ok('Some::Module'); ...some code that depends on the use... ...happening at compile time... }because the notion of "compile-time" is relative. Instead, you want: BEGIN { use_ok('Some::Module') } BEGIN { ...some code that depends on the use... }=cutsub use_ok ($;@) { my($module, @imports) = @_; @imports = () unless @imports; my $tb = Test::More->builder; my($pack,$filename,$line) = caller; # Work around a glitch in $@ and eval my $eval_error; { local($@,$!,$SIG{__DIE__}); # isolate eval if( @imports == 1 and $imports[0] =~ /^\d+(?:\.\d+)?$/ ) { # probably a version check. Perl needs to see the bare number # for it to work with non-Exporter based modules. eval <<USE;package $pack;use $module $imports[0];USE } else { eval <<USE;package $pack;use $module \@imports;USE } $eval_error = $@; } my $ok = $tb->ok( !$eval_error, "use $module;" ); unless( $ok ) { chomp $eval_error; $@ =~ s{^BEGIN failed--compilation aborted at .*$} {BEGIN failed--compilation aborted at $filename line $line.}m; $tb->diag(<<DIAGNOSTIC); Tried to use '$module'. Error: $eval_errorDIAGNOSTIC } return $ok;}=item B<require_ok> require_ok($module); require_ok($file);Like use_ok(), except it requires the $module or $file.=cutsub require_ok ($) { my($module) = shift; my $tb = Test::More->builder; my $pack = caller; # Try to deterine if we've been given a module name or file. # Module names must be barewords, files not. $module = qq['$module'] unless _is_module_name($module); local($!, $@, $SIG{__DIE__}); # isolate eval local $SIG{__DIE__}; eval <<REQUIRE;package $pack;require $module;REQUIRE my $ok = $tb->ok( !$@, "require $module;" ); unless( $ok ) { chomp $@; $tb->diag(<<DIAGNOSTIC); Tried to require '$module'. Error: $@DIAGNOSTIC } return $ok;}sub _is_module_name { my $module = shift; # Module names start with a letter. # End with an alphanumeric. # The rest is an alphanumeric or :: $module =~ s/\b::\b//g; $module =~ /^[a-zA-Z]\w*$/;}=back=head2 Complex data structuresNot everything is a simple eq check or regex. There are times youneed to see if two data structures are equivalent. For theseinstances Test::More provides a handful of useful functions.B<NOTE> I'm not quite sure what will happen with filehandles.=over 4=item B<is_deeply> is_deeply( $got, $expected, $test_name );Similar to is(), except that if $got and $expected are references, itdoes a deep comparison walking each data structure to see if they areequivalent. If the two structures are different, it will display theplace where they start differing.is_deeply() compares the dereferenced values of references, thereferences themselves (except for their type) are ignored. This meansaspects such as blessing and ties are not considered "different".is_deeply() current has very limited handling of function referenceand globs. It merely checks if they have the same referent. This mayimprove in the future.Test::Differences and Test::Deep provide more in-depth functionalityalong these lines.=cutuse vars qw(@Data_Stack %Refs_Seen);my $DNE = bless [], 'Does::Not::Exist';sub _dne { ref $_[0] eq ref $DNE;}sub is_deeply { my $tb = Test::More->builder; unless( @_ == 2 or @_ == 3 ) { my $msg = <<WARNING;is_deeply() takes two or three args, you gave %d.This usually means you passed an array or hash instead of a reference to itWARNING chop $msg; # clip off newline so carp() will put in line/file _carp sprintf $msg, scalar @_; return $tb->ok(0); } my($got, $expected, $name) = @_; $tb->_unoverload_str(\$expected, \$got); my $ok; if( !ref $got and !ref $expected ) { # neither is a reference $ok = $tb->is_eq($got, $expected, $name); } elsif( !ref $got xor !ref $expected ) { # one's a reference, one isn't $ok = $tb->ok(0, $name); $tb->diag( _format_stack({ vals => [ $got, $expected ] }) ); } else { # both references local @Data_Stack = (); if( _deep_check($got, $expected) ) { $ok = $tb->ok(1, $name); } else { $ok = $tb->ok(0, $name); $tb->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' : _dne($val) ? "Does not exist" : ref $val ? "$val" : "'$val'"; } $out .= "$vars[0] = $vals[0]\n"; $out .= "$vars[1] = $vals[1]\n"; $out =~ s/^/ /msg; return $out;}sub _type { my $thing = shift; return '' if !ref $thing; for my $type (qw(ARRAY HASH REF SCALAR GLOB CODE Regexp)) { return $type if UNIVERSAL::isa($thing, $type); } return '';}=back=head2 DiagnosticsIf you pick the right test function, you'll usually get a good idea ofwhat went wrong when it failed. But sometimes it doesn't work outthat way. So here we have ways for you to write your own diagnosticmessages which are safer than just C<print STDERR>.=over 4=item B<diag> diag(@diagnostic_message);Prints a diagnostic message which is guaranteed not to interfere withtest output. Like C<print> @diagnostic_message is simply concatenatedtogether.Handy for this sort of thing: ok( grep(/foo/, @users), "There's a foo user" ) or diag("Since there's no foo, check that /etc/bar is set up right");which would produce: not ok 42 - There's a foo user # Failed test 'There's a foo user' # in foo.t at line 52. # Since there's no foo, check that /etc/bar is set up right.You might remember C<ok() or diag()> with the mnemonic C<open() ordie()>.B<NOTE> The exact formatting of the diagnostic output is stillchanging, but it is guaranteed that whatever you throw at it it won'tinterfere with the test.=cutsub diag { my $tb = Test::More->builder; $tb->diag(@_);}=back=head2 Conditional testsSometimes running a test under certain conditions will cause thetest script to die. A certain function or method isn't implemented(such as fork() on MacOS), some resource isn't available (like a net connection) or a module isn't available. In these cases it'snecessary to skip tests, or declare that they are supposed to failbut will work in the future (a todo test).For more details on the mechanics of skip and todo tests seeL<Test::Harness>.The way Test::More handles this is with a named block. Basically, ablock of tests which can be skipped over or made todo. It's best if Ijust show you...=over 4=item B<SKIP: BLOCK> SKIP: { skip $why, $how_many if $condition; ...normal testing code goes here... }This declares a block of tests that might be skipped, $how_many teststhere are, $why and under what $condition to skip them. An example isthe easiest way to illustrate: SKIP: { eval { require HTML::Lint }; skip "HTML::Lint not installed", 2 if $@; my $lint = new HTML::Lint; isa_ok( $lint, "HTML::Lint" ); $lint->parse( $html ); is( $lint->errors, 0, "No errors found in HTML" ); }If the user does not have HTML::Lint installed, the whole block ofcode I<won't be run at all>. Test::More will output special ok'swhich Test::Harness interprets as skipped, but passing, tests.It's important that $how_many accurately reflects the number of testsin the SKIP block so the # of tests run will match up with your plan.If your plan is C<no_plan> $how_many is optional and will default to 1.It's perfectly safe to nest SKIP blocks. Each SKIP block must havethe label C<SKIP>, or Test::More can't work its magic.You don't skip tests which are failing because there's a bug in yourprogram, or for which you don't yet have code written. For that youuse TODO. Read on.=cut#'#sub skip { my($why, $how_many) = @_; my $tb = Test::More->builder; unless( defined $how_many ) { # $how_many can only be avoided when no_plan is in use. _carp "skip() needs to know \$how_many tests are in the block" unless $tb->has_plan eq 'no_plan'; $how_many = 1; } if( defined $how_many and $how_many =~ /\D/ ) { _carp "skip() was passed a non-numeric number of tests. Did you get the arguments backwards?"; $how_many = 1; } for( 1..$how_many ) { $tb->skip($why); } local $^W = 0; last SKIP;}=item B<TODO: BLOCK> TODO: { local $TODO = $why if $condition; ...normal testing code goes here... }Declares a block of tests you expect to fail and $why. Perhaps it'sbecause you haven't fixed a bug or haven't finished a new feature: TODO: { local $TODO = "URI::Geller not finished";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -