1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
|
NAME
Test::Base - A Data Driven Testing Framework
SYNOPSIS
A new test module:
# lib/MyProject/Test.pm
package MyProject::Test;
use Test::Base -Base;
use MyProject;
package MyProject::Test::Filter;
use Test::Base::Filter -base;
sub my_filter {
return MyProject->do_something(shift);
}
A sample test:
# t/sample.t
use MyProject::Test;
plan tests => 1 * blocks;
run_is input => 'expected';
sub local_filter {
s/my/your/;
}
__END__
=== Test one (the name of the test)
--- input my_filter local_filter
my
input
lines
--- expected
expected
output
=== Test two
This is an optional description
of this particular test.
--- input my_filter
other
input
lines
--- expected
other expected
output
DESCRIPTION
Testing is usually the ugly part of Perl module authoring. Perl gives
you a standard way to run tests with Test::Harness, and basic testing
primitives with Test::More. After that you are pretty much on your own
to develop a testing framework and philosophy. Test::More encourages you
to make your own framework by subclassing Test::Builder, but that is not
trivial.
Test::Base gives you a way to write your own test framework base class
that *is* trivial. In fact it is as simple as two lines:
package MyTestFramework;
use Test::Base -Base;
A module called "MyTestFramework.pm" containing those two lines, will
give all the power of Test::More and all the power of Test::Base to
every test file that uses it. As you build up the capabilities of
"MyTestFramework", your tests will have all of that power as well.
"MyTestFramework" becomes a place for you to put all of your reusable
testing bits. As you write tests, you will see patterns and duplication,
and you can "upstream" them into "MyTestFramework". Of course, you don't
have to subclass Test::Base at all. You can use it directly in many
applications, including everywhere you would use Test::More.
Test::Base concentrates on offering reusable data driven patterns, so
that you can write tests with a minimum of code. At the heart of all
testing you have inputs, processes and expected outputs. Test::Base
provides some clean ways for you to express your input and expected
output data, so you can spend your time focusing on that rather than
your code scaffolding.
EXPORTED FUNCTIONS
Test::Base extends Test::More and exports all of its functions. So you
can basically write your tests the same as Test::More. Test::Base also
exports many functions of its own:
is(actual, expected, [test-name])
This is the equivalent of Test::More's "is" function with one
interesting twist. If your actual and expected results differ and the
output is multi-line, this function will show you a unified diff format
of output. Consider the benefit when looking for the one character that
is different in hundreds of lines of output!
Diff output requires the optional "Text::Diff" CPAN module. If you don't
have this module, the "is()" function will simply give you normal
Test::More output. To disable diffing altogether, set the
"TEST_SHOW_NO_DIFFS" environment variable (or $ENV{TEST_SHOW_NO_DIFFS})
to a true value. You can also call the "no_diff" function as a shortcut.
blocks( [data-section-name] )
The most important function is "blocks". In list context it returns a
list of "Test::Base::Block" objects that are generated from the test
specification in the "DATA" section of your test file. In scalar context
it returns the number of objects. This is useful to calculate your
Test::More plan.
Each Test::Base::Block object has methods that correspond to the names
of that object's data sections. There is also a "name" and a
"description" method for accessing those parts of the block if they were
specified.
The "blocks" function can take an optional single argument, that
indicates to only return the blocks that contain a particular named data
section. Otherwise "blocks" returns all blocks.
my @all_of_my_blocks = blocks;
my @just_the_foo_blocks = blocks('foo');
next_block()
You can use the next_block function to iterate over all the blocks.
while (my $block = next_block) {
...
}
It returns undef after all blocks have been iterated over. It can then
be called again to reiterate.
first_block()
Returns the first block or undef if there are none. It resets the
iterator to the "next_block" function.
run(&subroutine)
There are many ways to write your tests. You can reference each block
individually or you can loop over all the blocks and perform a common
operation. The "run" function does the looping for you, so all you need
to do is pass it a code block to execute for each block.
The "run" function takes a subroutine as an argument, and calls the sub
one time for each block in the specification. It passes the current
block object to the subroutine.
run {
my $block = shift;
is(process($block->foo), $block->bar, $block->name);
};
run_is([data_name1, data_name2])
Many times you simply want to see if two data sections are equivalent in
every block, probably after having been run through one or more filters.
With the "run_is" function, you can just pass the names of any two data
sections that exist in every block, and it will loop over every block
comparing the two sections.
run_is 'foo', 'bar';
If no data sections are given "run_is" will try to detect them
automatically.
NOTE: Test::Base will silently ignore any blocks that don't contain both
sections.
is_deep($data1, $data2, $test_name)
Like Test::More's "is_deeply" but uses the more correct Test::Deep
module.
run_is_deeply([data_name1, data_name2])
Like "run_is_deeply" but uses "is_deep" which uses the more correct
Test::Deep.
run_is_deeply([data_name1, data_name2])
Like "run_is" but uses "is_deeply" for complex data structure
comparison.
run_is_deeply([data_name1, data_name2])
Like "run_is_deeply" but uses "is_deep" which uses the more correct
Test::Deep.
run_like([data_name, regexp | data_name]);
The "run_like" function is similar to "run_is" except the second
argument is a regular expression. The regexp can either be a "qr{}"
object or a data section that has been filtered into a regular
expression.
run_like 'foo', qr{<html.*};
run_like 'foo', 'match';
run_unlike([data_name, regexp | data_name]);
The "run_unlike" function is similar to "run_like", except the opposite.
run_unlike 'foo', qr{<html.*};
run_unlike 'foo', 'no_match';
run_compare(data_name1, data_name2)
The "run_compare" function is like the "run_is", "run_is_deeply" and the
"run_like" functions all rolled into one. It loops over each relevant
block and determines what type of comparison to do.
NOTE: If you do not specify either a plan, or run any tests, the
"run_compare" function will automatically be run.
delimiters($block_delimiter, $data_delimiter)
Override the default delimiters of "===" and "---".
spec_file($file_name)
By default, Test::Base reads its input from the DATA section. This
function tells it to get the spec from a file instead.
spec_string($test_data)
By default, Test::Base reads its input from the DATA section. This
function tells it to get the spec from a string that has been prepared
somehow.
filters( @filters_list or $filters_hashref )
Specify a list of additional filters to be applied to all blocks. See
FILTERS below.
You can also specify a hash ref that maps data section names to an array
ref of filters for that data type.
filters {
xxx => [qw(chomp lines)],
yyy => ['yaml'],
zzz => 'eval',
};
If a filters list has only one element, the array ref is optional.
filters_delay( [1 | 0] );
By default Test::Base::Block objects are have all their filters run
ahead of time. There are testing situations in which it is advantageous
to delay the filtering. Calling this function with no arguments or a
true value, causes the filtering to be delayed.
use Test::Base;
filters_delay;
plan tests => 1 * blocks;
for my $block (blocks) {
...
$block->run_filters;
ok($block->is_filtered);
...
}
In the code above, the filters are called manually, using the
"run_filters" method of Test::Base::Block. In functions like "run_is",
where the tests are run automatically, filtering is delayed until right
before the test.
filter_arguments()
Return the arguments after the equals sign on a filter.
sub my_filter {
my $args = filter_arguments;
# is($args, 'whazzup');
...
}
__DATA__
=== A test
--- data my_filter=whazzup
tie_output()
You can capture STDOUT and STDERR for operations with this function:
my $out = '';
tie_output(*STDOUT, $buffer);
print "Hey!\n";
print "Che!\n";
untie *STDOUT;
is($out, "Hey!\nChe!\n");
no_diff()
Turn off diff support for is() in a test file.
default_object()
Returns the default Test::Base object. This is useful if you feel the
need to do an OO operation in otherwise functional test code. See OO
below.
WWW() XXX() YYY() ZZZ()
These debugging functions are exported from the Spiffy.pm module. See
Spiffy for more info.
croak() carp() cluck() confess()
You can use the functions from the Carp module without needing to import
them. Test::Base does it for you by default.
TEST SPECIFICATION
Test::Base allows you to specify your test data in an external file, the
DATA section of your program or from a scalar variable containing all
the text input.
A *test specification* is a series of text lines. Each test (or block)
is separated by a line containing the block delimiter and an optional
test "name". Each block is further subdivided into named sections with a
line containing the data delimiter and the data section name. A
"description" of the test can go on lines after the block delimiter but
before the first data section.
Here is the basic layout of a specification:
=== <block name 1>
<optional block description lines>
--- <data section name 1> <filter-1> <filter-2> <filter-n>
<test data lines>
--- <data section name 2> <filter-1> <filter-2> <filter-n>
<test data lines>
--- <data section name n> <filter-1> <filter-2> <filter-n>
<test data lines>
=== <block name 2>
<optional block description lines>
--- <data section name 1> <filter-1> <filter-2> <filter-n>
<test data lines>
--- <data section name 2> <filter-1> <filter-2> <filter-n>
<test data lines>
--- <data section name n> <filter-1> <filter-2> <filter-n>
<test data lines>
Here is a code example:
use Test::Base;
delimiters qw(### :::);
# test code here
__END__
### Test One
We want to see if foo and bar
are really the same...
::: foo
a foo line
another foo line
::: bar
a bar line
another bar line
### Test Two
::: foo
some foo line
some other foo line
::: bar
some bar line
some other bar line
::: baz
some baz line
some other baz line
This example specifies two blocks. They both have foo and bar data
sections. The second block has a baz component. The block delimiter is
"###" and the data delimiter is ":::".
The default block delimiter is "===" and the default data delimiter is
"---".
There are some special data section names used for control purposes:
--- SKIP
--- ONLY
--- LAST
A block with a SKIP section causes that test to be ignored. This is
useful to disable a test temporarily.
A block with an ONLY section causes only that block to be used. This is
useful when you are concentrating on getting a single test to pass. If
there is more than one block with ONLY, the first one will be chosen.
Because ONLY is very useful for debugging and sometimes you forgot to
remove the ONLY flag before commiting to the VCS or uploading to CPAN,
Test::Base by default gives you a diag message saying *I found ONLY ...
maybe you're debugging?*. If you don't like it, use "no_diag_on_only".
A block with a LAST section makes that block the last one in the
specification. All following blocks will be ignored.
FILTERS
The real power in writing tests with Test::Base comes from its filtering
capabilities. Test::Base comes with an ever growing set of useful
generic filters than you can sequence and apply to various test blocks.
That means you can specify the block serialization in the most readable
format you can find, and let the filters translate it into what you
really need for a test. It is easy to write your own filters as well.
Test::Base allows you to specify a list of filters to each data section
of each block. The default filters are "norm" and "trim". These filters
will be applied (in order) to the data after it has been parsed from the
specification and before it is set into its Test::Base::Block object.
You can add to the default filter list with the "filters" function. You
can specify additional filters to a specific block by listing them after
the section name on a data section delimiter line.
Example:
use Test::Base;
filters qw(foo bar);
filters { perl => 'strict' };
sub upper { uc(shift) }
__END__
=== Test one
--- foo trim chomp upper
...
--- bar -norm
...
--- perl eval dumper
my @foo = map {
- $_;
} 1..10;
\ @foo;
Putting a "-" before a filter on a delimiter line, disables that filter.
Scalar vs List
Each filter can take either a scalar or a list as input, and will return
either a scalar or a list. Since filters are chained together, it is
important to learn which filters expect which kind of input and return
which kind of output.
For example, consider the following filter list:
norm trim lines chomp array dumper eval
The data always starts out as a single scalar string. "norm" takes a
scalar and returns a scalar. "trim" takes a list and returns a list, but
a scalar is a valid list. "lines" takes a scalar and returns a list.
"chomp" takes a list and returns a list. "array" takes a list and
returns a scalar (an anonymous array reference containing the list
elements). "dumper" takes a list and returns a scalar. "eval" takes a
scalar and creates a list.
A list of exactly one element works fine as input to a filter requiring
a scalar, but any other list will cause an exception. A scalar in list
context is considered a list of one element.
Data accessor methods for blocks will return a list of values when used
in list context, and the first element of the list in scalar context.
This is usually "the right thing", but be aware.
The Stock Filters
Test::Base comes with large set of stock filters. They are in the
"Test::Base::Filter" module. See Test::Base::Filter for a listing and
description of these filters.
Rolling Your Own Filters
Creating filter extensions is very simple. You can either write a
*function* in the "main" namespace, or a *method* in the
"Test::Base::Filter" namespace or a subclass of it. In either case the
text and any extra arguments are passed in and you return whatever you
want the new value to be.
Here is a self explanatory example:
use Test::Base;
filters 'foo', 'bar=xyz';
sub foo {
transform(shift);
}
sub Test::Base::Filter::bar {
my $self = shift; # The Test::Base::Filter object
my $data = shift;
my $args = $self->current_arguments;
my $current_block_object = $self->block;
# transform $data in a barish manner
return $data;
}
If you use the method interface for a filter, you can access the block
internals by calling the "block" method on the filter object.
Normally you'll probably just use the functional interface, although all
the builtin filters are methods.
Note that filters defined in the "main" namespace can look like:
sub filter9 {
s/foo/bar/;
}
since Test::Base automatically munges the input string into $_ variable
and checks the return value of the function to see if it looks like a
number. If you must define a filter that returns just a single number,
do it in a different namespace as a method. These filters don't allow
the simplistic $_ munging.
OO
Test::Base has a nice functional interface for simple usage. Under the
hood everything is object oriented. A default Test::Base object is
created and all the functions are really just method calls on it.
This means if you need to get fancy, you can use all the object oriented
stuff too. Just create new Test::Base objects and use the functions as
methods.
use Test::Base;
my $blocks1 = Test::Base->new;
my $blocks2 = Test::Base->new;
$blocks1->delimiters(qw(!!! @@@))->spec_file('test1.txt');
$blocks2->delimiters(qw(### $$$))->spec_string($test_data);
plan tests => $blocks1->blocks + $blocks2->blocks;
# ... etc
THE "Test::Base::Block" CLASS
In Test::Base, blocks are exposed as Test::Base::Block objects. This
section lists the methods that can be called on a Test::Base::Block
object. Of course, each data section name is also available as a method.
name()
This is the optional short description of a block, that is specified on
the block separator line.
description()
This is an optional long description of the block. It is the text taken
from between the block separator and the first data section.
seq_num()
Returns a sequence number for this block. Sequence numbers begin with 1.
blocks_object()
Returns the Test::Base object that owns this block.
run_filters()
Run the filters on the data sections of the blocks. You don't need to
use this method unless you also used the "filters_delay" function.
is_filtered()
Returns true if filters have already been run for this block.
original_values()
Returns a hash of the original, unfiltered values of each data section.
SUBCLASSING
One of the nicest things about Test::Base is that it is easy to
subclass. This is very important, because in your personal project, you
will likely want to extend Test::Base with your own filters and other
reusable pieces of your test framework.
Here is an example of a subclass:
package MyTestStuff;
use Test::Base -Base;
our @EXPORT = qw(some_func);
sub some_func {
(my ($self), @_) = find_my_self(@_);
...
}
package MyTestStuff::Block;
use base 'Test::Base::Block';
sub desc {
$self->description(@_);
}
package MyTestStuff::Filter;
use base 'Test::Base::Filter';
sub upper {
$self->assert_scalar(@_);
uc(shift);
}
Note that you don't have to re-Export all the functions from Test::Base.
That happens automatically, due to the powers of Spiffy.
The first line in "some_func" allows it to be called as either a
function or a method in the test code.
DISTRIBUTION SUPPORT
You might be thinking that you do not want to use Test::Base in you
modules, because it adds an installation dependency. Fear not.
Module::Install takes care of that.
Just write a Makefile.PL that looks something like this:
use inc::Module::Install;
name 'Foo';
all_from 'lib/Foo.pm';
use_test_base;
WriteAll;
The line with "use_test_base" will automatically bundle all the code the
user needs to run Test::Base based tests.
OTHER COOL FEATURES
Test::Base automatically adds:
use strict;
use warnings;
to all of your test scripts and Test::Base subclasses. A Spiffy feature
indeed.
HISTORY
This module started its life with the horrible and ridicule inducing
name "Test::Chunks". It was renamed to "Test::Base" with the hope that
it would be seen for the very useful module that it has become. If you
are switching from "Test::Chunks" to "Test::Base", simply substitute the
concept and usage of "chunks" to "blocks".
AUTHOR
Ingy dt Net <ingy@cpan.org>
COPYRIGHT
Copyright (c) 2006, 2008, 2009. Ingy dt Net. Copyright (c) 2005. Brian
Ingerson.
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
|