5
# ABSTRACT: Composable, reusable tests with roles and Moo
6
our $VERSION = '1.002'; # VERSION
8
use Test::More 0.96 import => [qw/subtest/];
13
my ( $class, @args ) = @_;
15
for my $sub (qw/test run_me/) {
16
Sub::Install::install_sub( { into => $caller, code => $sub } );
18
strictures->import; # do this for Moo, since we load Moo in eval
22
extends 'Test::Roo::Class'
25
eval qq{ package $caller; use Test::More \@args };
28
eval qq{ package $caller; use Test::More };
34
my ( $name, $code ) = @_;
38
subtest $name => sub { $self->each_test($code) }
40
eval qq{ package $caller; after _do_tests => \$subtest };
46
$class->run_tests(@_);
52
# vim: ts=4 sts=4 sw=4 et:
62
Test::Roo - Composable, reusable tests with roles and Moo
70
Define test behaviors and required fixtures in a role:
72
# t/lib/ObjectCreation.pm
74
package ObjectCreation;
75
use Test::Roo::Role; # loads Moo::Role and Test::More
77
requires 'class'; # we need this fixture
79
test 'object creation' => sub {
81
require_ok( $self->class );
82
my $obj = new_ok( $self->class );
87
Provide fixtures and run tests from the .t file:
91
use Test::Roo; # loads Moo and Test::More
97
default => sub { "Digest::MD5" },
100
# specify behaviors to test
101
with 'ObjectCreation';
103
# give our subtests a pretty label
104
sub _build_description { "Testing " . shift->class }
106
# run the test with default fixture
109
# run the test with different fixture
110
run_me( { class => "Digest::SHA1" } );
118
ok 1 - require Digest::MD5;
119
ok 2 - The object isa Digest::MD5
121
ok 1 - object creation
123
ok 1 - Testing Digest::MD5
124
ok 1 - require Digest::SHA1;
125
ok 2 - The object isa Digest::SHA1
127
ok 1 - object creation
129
ok 2 - Testing Digest::SHA1
132
All tests successful.
133
Files=1, Tests=2, 0 wallclock secs ( 0.02 usr 0.01 sys + 0.06 cusr 0.00 csys = 0.09 CPU)
138
This module allows you to compose L<Test::More> tests from roles. It is
139
inspired by the excellent L<Test::Routine> module, but uses L<Moo> instead of
140
L<Moose>. This gives most of the benefits without the need for L<Moose> as a
143
Test files are Moo classes. You can define any needed test fixtures as Moo
144
attributes. You define tests as method modifiers -- similar in concept to
145
C<subtest> in L<Test::More>, but your test method will be passed the test
146
object for access to fixture attributes. You may compose any L<Moo::Role> into
147
your test to define attributes, require particular methods, or define tests.
149
This means that you can isolate test I<behaviors> into roles which require
150
certain test I<fixtures> in order to run. Your main test file will provide the
151
fixtures and compose the roles to run. This makes it easy to reuse test
154
For example, if you are creating tests for Awesome::Module, you could create
155
the test behaviors as Awesome::Module::Test::Role and distribute it with
156
your module. If another distribution subclasses Awesome::Module, it can
157
compose the Awesome::Module::Test::Role behavior for its own tests.
159
No more copying and pasting tests from a super class! Superclasses define and
160
share their tests. Subclasses provide their own fixtures and run the tests.
162
=for Pod::Coverage add_methods_here
166
Importing L<Test::Roo> also loads L<Moo> (which gives you L<strictures> with
167
fatal warnings and other goodies) and makes the current package a subclass
168
of L<Test::Roo::Class>.
170
Importing also loads L<Test::More>. No test plan is used. The C<done_testing>
171
function must be used at the end of every test file. Any import arguments are
172
passed through to Test::More's C<import> method.
174
See also L<Test::Roo::Role> for test role usage.
176
=head2 Creating fixtures
178
You can create fixtures with normal Moo syntax. You can even make them lazy if
185
sub _build_fixture { ... }
187
This becomes really useful with L<Test::Roo::Role>. A role could define the
188
attribute and require the builder method to be provided by the main test class.
190
=head2 Composing test roles
192
You can use roles to define units of test behavior and then compose them into
193
your test class using the C<with> function. Test roles may define attributes,
194
declare tests, require certain methods and anything else you can regularly do
199
with 'MyTestRole1', 'MyTestRole2';
201
See L<Test::Roo::Role> and the L<Test::Roo::Cookbook> for details and
204
=head2 Setup and teardown
206
You can add method modifiers around the C<setup> and C<teardown> methods and
207
these will be run before tests begin and after tests finish (respectively).
209
before setup => sub { ... };
211
after teardown => sub { ... };
213
You can also add method modifiers around C<each_test>, which will be
214
run before and after B<every> individual test. You could use these to
215
prepare or reset a fixture.
217
has fixture => ( is => 'lazy, clearer => 1, predicate => 1 );
219
after each_test => sub { shift->clear_fixture };
221
Roles may also modify C<setup>, C<teardown>, and C<each_test>, so the order
222
that modifiers will be called will depend on when roles are composed. Be
223
careful with C<each_test>, though, because the global effect may make
224
composition more fragile.
226
You can call test functions in modifiers. For example, you could
227
confirm that something has been set up or cleaned up.
229
before each_test => sub { ok( ! shift->has_fixture ) };
233
The simplest way to use L<Test::Roo> with a single F<.t> file is to let the
234
C<main> package be the test class and call C<run_me> in it:
237
use Test::Roo; # loads Moo and Test::More
241
default => sub { "Digest::MD5" },
244
test 'load class' => sub {
246
require_ok( $self->class );
252
Calling C<< run_me(@args) >> is equivalent to calling
253
C<< __PACKAGE__->run_tests(@args) >> and runs tests for the current package.
255
You may specify an optional description or hash reference of constructor
256
arguments to customize the test object:
258
run_me( "load MD5" );
259
run_me( { class => "Digest::MD5" } );
260
run_me( "load MD5", { class => "Digest::MD5" } );
262
See L<Test::Roo::Class> for more about the C<run_tests> method.
264
Alternatively, you can create a separate package (in the test file or in a
265
separate F<.pm> file) and run tests explicitly on that class.
284
for my $c ( qw/Digest::MD5 Digest::SHA/ ) {
285
MyTest->run_tests("Testing $c", { class => $c } );
290
=head1 EXPORTED FUNCTIONS
292
Loading L<Test::Roo> exports subroutines into the calling package to declare
297
test $label => sub { ... };
299
The C<test> function adds a subtest. The code reference will be called with
300
the test object as its only argument.
302
Tests are run in the order declared, so the order of tests from roles will
303
depend on when they are composed relative to other test declarations.
308
run_me( $description );
309
run_me( $init_args );
310
run_me( $description, $init_args );
312
The C<run_me> function calls the C<run_tests> method on the current package
313
and passes all arguments to that method. It takes a description and/or
314
a hash reference of constructor arguments.
316
=head1 DIFFERENCES FROM TEST::ROUTINE
318
While this module was inspired by L<Test::Routine>, it is not a drop-in
319
replacement. Here is an overview of major differences:
325
L<Test::Roo> uses L<Moo>; L<Test::Routine> uses L<Moose>
329
Loading L<Test::Roo> makes the importing package a class; in L<Test::Routine> it becomes a role
333
Loading L<Test::Roo> loads L<Test::More>; L<Test::Routine> does not
337
In L<Test::Roo>, C<run_test> is a method; in L<Test::Routine> it is a function and takes arguments in a different order
341
In L<Test::Roo>, all role composition must be explicit using C<with>; in L<Test::Routine>, the C<run_tests> command can also compose roles
345
In L<Test::Roo>, test blocks become method modifiers hooked on an empty method; in L<Test::Routine>, they become methods run via introspection
349
In L<Test::Roo>, setup and teardown are done by modifying C<setup> and C<teardown> methods; in L<Test::Routine> they are done by modifying C<run_test>
353
=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
357
=head2 Bugs / Feature Requests
359
Please report any bugs or feature requests through the issue tracker
360
at L<https://github.com/dagolden/Test-Roo/issues>.
361
You will be notified automatically of any progress on your issue.
365
This is open source software. The code repository is available for
366
public review and contribution under the terms of the license.
368
L<https://github.com/dagolden/Test-Roo>
370
git clone https://github.com/dagolden/Test-Roo.git
374
David Golden <dagolden@cpan.org>
378
Diab Jerius <djerius@gmail.com>
380
=head1 COPYRIGHT AND LICENSE
382
This software is Copyright (c) 2013 by David Golden.
384
This is free software, licensed under:
386
The Apache License, Version 2.0, January 2004