NAME
Test::Stream::Tester - Tools for validating the events produced by your testing tools.
DESCRIPTION
There are tools to validate your code. This library provides tools to validate your tools!
SYNOPSIS
use Test::More;
use Test::Stream::Tester;
events_are(
# Capture all the events within the block
intercept {
ok(1, "pass");
ok(0, "fail");
diag("xxx");
},
# Describe what we expect to see
check {
event ok => {bool => 1, name => 'pass'};
event ok => {
bool => 0,
name => 'fail',
# Ignores any fields in the result we don't list
# real_bool, line, file, tool_package, tool_name, etc...
# Diagnostics generated by a test are typically linked to those
# results (new and updated tools only) They can be validated.
diag => qr/^Failed test /,
};
event diag => {message => 'xxx'};
directive 'end'; # enforce that there are no more results
},
"This is the name of our test"
);
done_testing;
GRAB WITH NO ADDED STACK
use Test::More;
use Test::Stream::Tester;
# Start capturing events. We use grab() instead of intercept {} to avoid
# adding stack frames.
my $grab = grab();
# Generate some events.
ok(1, "pass");
ok(0, "fail");
diag("xxx");
# Stop capturing events, and validate the ones recieved.
events_are(
$grab,
check {
event ok => { bool => 1, name => 'pass' };
event ok => { bool => 0, name => 'fail' };
event diag => { message => 'xxx' };
directive 'end';
},
'Validate our Grab results';
);
# $grab is now undef, it no longer exists.
is($grab, undef, '$grab was destroyed for us.');
ok(!$success, "Eval did not succeed, BAIL_OUT killed the test");
# Make sure we got the event as an exception
isa_ok($error, 'Test::Stream::Event::Bail');
done_testing
EXPORTS
- $events = intercept { ... }
- $events = intercept(sub { ... })
-
Capture the Test::Builder::Event objects generated by tests inside the block.
- events_are(\@events, $check)
- events_are(\@events, $check, $name)
- events_are($events, $check)
- events_are($events, $check, $name)
- events_are($grab, $check)
- events_are($grab, $check, $name)
-
The first argument may be either an arrayref of Test::Stream::Event objects, an Test::Stream::Tester::Grab object, or an Test::Stream::Tester::Events object.
intercept { ... }
can be used to capture events within a block of code, including plans such asskip_all
, and things that normally kill the test likeBAIL_OUT()
.The second argument must be an Test::Stream::Tester::Checks object. Typically these are generated using
check { ... }
.The third argument is the name of the test, it is optional, but highly recommended.
- $checks = check { ... };
-
Produce an array of expected events for use in events_are.
my $check = check { event ok => { ... }; event diag => { ... }; directive 'end'; };
If the block passed to check returns anything at all it will warn you as this usually means you forgot to use the
event
and/ordiag
functions. If it returns something AND has no events it will be fatal.event()
anddirective()
both return nothing, this means that if you use them alone your codeblock will return nothing. - event TYPE => { ... };
-
Define an event and push it onto the list that will be returned by the enclosing
check { ... }
block. Will fail if run outside a check block. This will fail if you give it an invalid event type.If you wish to acknowledge the event, but not check anything you may simply give it an empty hashref.
The line number where the event was generated is recorded for helpful debugging in event of a failure.
CAVEAT The line number is inexact because of the way perl records it. The line number is taken from
caller
. - dir 'DIRECTIVE';
- dir DIRECTIVE => 'ARG';
- dir sub { ... };
- dir sub { ... }, $arg;
- directive 'DIRECTIVE';
- directive DIRECTIVE => 'ARG';
- directive sub { ... };
- directive sub { ... }, $arg;
-
Define a directive and push it onto the list that will be returned by the enclosing
check { ... }
block. This will fail if run outside of a check block.The first argument must be either a codeblock, or one of the name of a predefined directive See the directives section.
Coderefs will be given 3 arguments:
sub { my ($checks, $events, $arg) = @_; ... }
$checks
is the Test::Stream::Tester::Checks object.$events
is the Test::Stream::Tester::Events object.$arg
is whatever argument you passed via thedirective()
call.Most directives will act on the
$events
object to remove or alter events.
INTERCEPTING EVENTS
my $events = intercept {
ok(1, "pass");
ok(0, "fail");
diag("xxx");
};
Any events generated within the block will be intercepted and placed inside the $events
array reference.
EVENT TYPES
All events will be subclasses of Test::Builder::Event
- Test::Builder::Event::Ok
- Test::Builder::Event::Note
- Test::Builder::Event::Diag
- Test::Builder::Event::Plan
- Test::Builder::Event::Finish
- Test::Builder::Event::Bail
- Test::Builder::Event::Subtest
VALIDATING EVENTS
You can validate events by hand using traditional test tools such as is_deeply()
against the $events array returned from intercept()
. However it is easier to use events_are()
paried with checks
objects build using checks { ... }
.
events_are(
intercept {
ok(1, "pass");
ok(0, "fail");
diag("xxx");
},
check {
event ok => { bool => 1, name => 'pass' };
event ok => { bool => 0, name => 'fail' };
event diag => {message => 'xxx'};
directive 'end';
},
"This is the name of our test"
);
WHAT DOES THIS BUY ME?
checks { ... }
, event()
, and directive()
, work together to produce a nested set of objects to represent what you want to see. This was chosen over a hash/list system for 2 reasons:
- Better Diagnostics
-
Whenever you use
checks { ... }
,events()
, anddirective()
it records the filename and line number where they are called. When a test fails the diagnostics will include this information so that you know where the error occured. In a hash/list based system this information is not available.A hash based system is not practical as you may generate several events of the same type, and in a hash duplicated keys are squashed (last one wins).
A list based system works, but then a failure reports the index of the failure, this requires you to manually count events to find the correct one. Originally I tried letting you specify an ID for the events, but this proved annoying.
Ultimately I am very happy with the diagnostics this allows. It is very nice to see what is essentially a simple trace showing where the event and check were generated. It also shows you the items leading to the failure in the event of nested checks.
- Loops and other constructs
-
In a list based system you are limited in what you can produce. You can generate the list in advance, then pass it in, but this is hard to debug. Alternatively you can use
map
to produce repeated events, but this is equally hard to debug.This system lets you call
event()
anddirective()
in loops directly. It also lets you write functions that produce them based on input for reusable test code.
VALIDATING FIELDS
The hashref against which events are checked is composed of keys, and values. The values may be regular values, which are checked for equality with the corresponding property of the event object. Alternatively you can provide a regex to match against, or an arrayref of regexes (each one must match).
- field => 'exact_value',
-
The specified field must exactly match the given value, be it number or string.
- field => qr/.../,
-
The specified field must match the regular expression.
- field => [qr/.../, qr/.../, ...],
-
The value of the field must match ALL the regexes.
- field => sub { ... }
-
Specify a sub that will validate the value of the field.
foo => sub { my ($key, $val) = @_; ... # Return true (valid) or false, and any desired diagnostics messages. return($bool, @diag); },
WHAT FIELDS ARE AVAILABLE?
This is specific to the event type. All events inherit from Test::Builder::Event which provides a summary()
method. The summary()
method returns a list of key/value pairs (not a reference!) with all fields that are for public consumption.
For each of the following modules see the SUMMARY FIELDS section for a list of fields made available. These fields are inherited when events are subclassed, and all events have the summary fields present in Test::Builder::Event.
- "SUMMARY FIELDS" in Test::Builder::Event
- "SUMMARY FIELDS" in Test::Builder::Event::Ok
- "SUMMARY FIELDS" in Test::Builder::Event::Note
- "SUMMARY FIELDS" in Test::Builder::Event::Diag
- "SUMMARY FIELDS" in Test::Builder::Event::Plan
- "SUMMARY FIELDS" in Test::Builder::Event::Finish
- "SUMMARY FIELDS" in Test::Builder::Event::Bail
- "SUMMARY FIELDS" in Test::Builder::Event::Subtest
DIRECTIVES
Directives give you a chance to alter the list of events part-way through the check, or to make the check skip/ignore events based on conditions.
skip
Skip will skip a specific number of events at that point in the check.
- directive skip => $num;
-
my $events = intercept { ok(1, "foo"); diag("XXX"); ok(1, "bar"); diag("YYY"); ok(1, "baz"); diag("ZZZ"); }; events_are( $events, ok => { name => "foo" }, skip => 1, # Skips the diag 'XXX' ok => { name => "bar" }, skip => 2, # Skips the diag 'YYY' and the ok 'baz' diag => { message => 'ZZZ' }, );
seek
When turned on (true), any unexpected events will be skipped. You can turn this on and off any time by using it again with a false argument.
- directive seek => $BOOL;
-
my $events = intercept { ok(1, "foo"); diag("XXX"); diag("YYY"); ok(1, "bar"); diag("ZZZ"); ok(1, "baz"); }; events_are( $events, seek => 1, ok => { name => "foo" }, # The diags are ignored, it will seek to the next 'ok' ok => { name => "bar" }, seek => 0, # This will fail because the diag is not ignored anymore. ok => { name => "baz" }, );
end
Used to say that there should not be any more events. Without this any events after your last check are simply ignored. This will generate a failure if any unchecked events remain.
SEE ALSO
- Test::Tester *Deprecated*
-
A nice, but very limited tool for testing 'ok' results.
- Test::Builder::Tester *Deprecated*
-
The original test tester, checks TAP output as giant strings.
SOURCE
The source code repository for Test::More can be found at http://github.com/Test-More/test-more/.
MAINTAINER
AUTHORS
The following people have all contributed to the Test-More dist (sorted using VIM's sort function).
- Chad Granum <exodist@cpan.org>
- Fergal Daly <fergal@esatclear.ie>>
- Mark Fowler <mark@twoshortplanks.com>
- Michael G Schwern <schwern@pobox.com>
- 唐鳳
COPYRIGHT
There has been a lot of code migration between modules, here are all the original copyrights together:
- Test::Stream
- Test::Stream::Tester
-
Copyright 2014 Chad Granum <exodist7@gmail.com>.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
See http://www.perl.com/perl/misc/Artistic.html
- Test::Simple
- Test::More
- Test::Builder
-
Originally authored by Michael G Schwern <schwern@pobox.com> with much inspiration from Joshua Pritikin's Test module and lots of help from Barrie Slaymaker, Tony Bowden, blackstar.co.uk, chromatic, Fergal Daly and the perl-qa gang.
Idea by Tony Bowden and Paul Johnson, code by Michael G Schwern <schwern@pobox.com>, wardrobe by Calvin Klein.
Copyright 2001-2008 by Michael G Schwern <schwern@pobox.com>.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
See http://www.perl.com/perl/misc/Artistic.html
- Test::use::ok
-
To the extent possible under law, 唐鳳 has waived all copyright and related or neighboring rights to Test-use-ok.
This work is published from Taiwan.
- Test::Tester
-
This module is copyright 2005 Fergal Daly <fergal@esatclear.ie>, some parts are based on other people's work.
Under the same license as Perl itself
See http://www.perl.com/perl/misc/Artistic.html
- Test::Builder::Tester
-
Copyright Mark Fowler <mark@twoshortplanks.com> 2002, 2004.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.