1NAME
2 Test::Roo - Composable, reusable tests with roles and Moo
3
4VERSION
5 version 1.004
6
7SYNOPSIS
8 Define test behaviors and required fixtures in a role:
9
10 # t/lib/ObjectCreation.pm
11
12 package ObjectCreation;
13 use Test::Roo::Role; # loads Moo::Role and Test::More
14
15 requires 'class'; # we need this fixture
16
17 test 'object creation' => sub {
18 my $self = shift;
19 require_ok( $self->class );
20 my $obj = new_ok( $self->class );
21 };
22
23 1;
24
25 Provide fixtures and run tests from the .t file:
26
27 # t/test.t
28
29 use Test::Roo; # loads Moo and Test::More
30 use lib 't/lib';
31
32 # provide the fixture
33 has class => (
34 is => 'ro',
35 default => sub { "Digest::MD5" },
36 );
37
38 # specify behaviors to test
39 with 'ObjectCreation';
40
41 # give our subtests a pretty label
42 sub _build_description { "Testing " . shift->class }
43
44 # run the test with default fixture
45 run_me;
46
47 # run the test with different fixture
48 run_me( { class => "Digest::SHA1" } );
49
50 done_testing;
51
52 Result:
53
54 $ prove -lv t
55 t/test.t ..
56 ok 1 - require Digest::MD5;
57 ok 2 - The object isa Digest::MD5
58 1..2
59 ok 1 - object creation
60 1..1
61 ok 1 - Testing Digest::MD5
62 ok 1 - require Digest::SHA1;
63 ok 2 - The object isa Digest::SHA1
64 1..2
65 ok 1 - object creation
66 1..1
67 ok 2 - Testing Digest::SHA1
68 1..2
69 ok
70 All tests successful.
71 Files=1, Tests=2, 0 wallclock secs ( 0.02 usr 0.01 sys + 0.06 cusr 0.00 csys = 0.09 CPU)
72 Result: PASS
73
74DESCRIPTION
75 This module allows you to compose Test::More tests from roles. It is
76 inspired by the excellent Test::Routine module, but uses Moo instead of
77 Moose. This gives most of the benefits without the need for Moose as a
78 test dependency.
79
80 Test files are Moo classes. You can define any needed test fixtures as
81 Moo attributes. You define tests as method modifiers -- similar in
82 concept to "subtest" in Test::More, but your test method will be passed
83 the test object for access to fixture attributes. You may compose any
84 Moo::Role into your test to define attributes, require particular
85 methods, or define tests.
86
87 This means that you can isolate test *behaviors* into roles which
88 require certain test *fixtures* in order to run. Your main test file
89 will provide the fixtures and compose the roles to run. This makes it
90 easy to reuse test behaviors.
91
92 For example, if you are creating tests for Awesome::Module, you could
93 create the test behaviors as Awesome::Module::Test::Role and distribute
94 it with your module. If another distribution subclasses Awesome::Module,
95 it can compose the Awesome::Module::Test::Role behavior for its own
96 tests.
97
98 No more copying and pasting tests from a super class! Superclasses
99 define and share their tests. Subclasses provide their own fixtures and
100 run the tests.
101
102USAGE
103 Importing Test::Roo also loads Moo (which gives you strictures with
104 fatal warnings and other goodies) and makes the current package a
105 subclass of Test::Roo::Class.
106
107 Importing also loads Test::More. No test plan is used. The
108 "done_testing" function must be used at the end of every test file. Any
109 import arguments are passed through to Test::More's "import" method.
110
111 See also Test::Roo::Role for test role usage.
112
113 Creating fixtures
114 You can create fixtures with normal Moo syntax. You can even make them
115 lazy if you want:
116
117 has fixture => (
118 is => 'lazy'
119 );
120
121 sub _build_fixture { ... }
122
123 This becomes really useful with Test::Roo::Role. A role could define the
124 attribute and require the builder method to be provided by the main test
125 class.
126
127 Composing test roles
128 You can use roles to define units of test behavior and then compose them
129 into your test class using the "with" function. Test roles may define
130 attributes, declare tests, require certain methods and anything else you
131 can regularly do with roles.
132
133 use Test::Roo;
134
135 with 'MyTestRole1', 'MyTestRole2';
136
137 See Test::Roo::Role and the Test::Roo::Cookbook for details and
138 examples.
139
140 Setup and teardown
141 You can add method modifiers around the "setup" and "teardown" methods
142 and these will be run before tests begin and after tests finish
143 (respectively).
144
145 before setup => sub { ... };
146
147 after teardown => sub { ... };
148
149 You can also add method modifiers around "each_test", which will be run
150 before and after every individual test. You could use these to prepare
151 or reset a fixture.
152
153 has fixture => ( is => 'lazy, clearer => 1, predicate => 1 );
154
155 after each_test => sub { shift->clear_fixture };
156
157 Roles may also modify "setup", "teardown", and "each_test", so the order
158 that modifiers will be called will depend on when roles are composed. Be
159 careful with "each_test", though, because the global effect may make
160 composition more fragile.
161
162 You can call test functions in modifiers. For example, you could confirm
163 that something has been set up or cleaned up.
164
165 before each_test => sub { ok( ! shift->has_fixture ) };
166
167 Running tests
168 The simplest way to use Test::Roo with a single .t file is to let the
169 "main" package be the test class and call "run_me" in it:
170
171 # t/test.t
172 use Test::Roo; # loads Moo and Test::More
173
174 has class => (
175 is => 'ro',
176 default => sub { "Digest::MD5" },
177 );
178
179 test 'load class' => sub {
180 my $self = shift;
181 require_ok( $self->class );
182 }
183
184 run_me;
185 done_testing;
186
187 Calling "run_me(@args)" is equivalent to calling
188 "__PACKAGE__->run_tests(@args)" and runs tests for the current package.
189
190 You may specify an optional description or hash reference of constructor
191 arguments to customize the test object:
192
193 run_me( "load MD5" );
194 run_me( { class => "Digest::MD5" } );
195 run_me( "load MD5", { class => "Digest::MD5" } );
196
197 See Test::Roo::Class for more about the "run_tests" method.
198
199 Alternatively, you can create a separate package (in the test file or in
200 a separate .pm file) and run tests explicitly on that class.
201
202 # t/test.t
203 package MyTest;
204 use Test::Roo;
205
206 use lib 't/lib';
207
208 has class => (
209 is => 'ro',
210 required => 1,
211 );
212
213 with 'MyTestRole';
214
215 package main;
216 use strictures;
217 use Test::More;
218
219 for my $c ( qw/Digest::MD5 Digest::SHA/ ) {
220 MyTest->run_tests("Testing $c", { class => $c } );
221 }
222
223 done_testing;
224
225EXPORTED FUNCTIONS
226 Loading Test::Roo exports subroutines into the calling package to
227 declare and run tests.
228
229 test
230 test $label => sub { ... };
231
232 The "test" function adds a subtest. The code reference will be called
233 with the test object as its only argument.
234
235 Tests are run in the order declared, so the order of tests from roles
236 will depend on when they are composed relative to other test
237 declarations.
238
239 top_test
240 top_test $label => sub { ... };
241
242 The "top_test" function adds a "top level" test. Works exactly like
243 "test" except it will not start a subtest. This is especially useful in
244 very simple testing situations where the extra subtest level is just
245 noise.
246
247 So for example the following test
248
249 # t/test.t
250 use Test::Roo;
251
252 has class => (
253 is => 'ro',
254 required => 1,
255 );
256
257 top_test basic => sub {
258 my $self = shift;
259
260 require_ok($self->class);
261 isa_ok($self->class->new, $self->class);
262 };
263
264 for my $c ( qw/Digest::MD5 Digest::SHA/ ) {
265 run_me("Testing $c", { class => $c } );
266 }
267
268 done_testing;
269
270 produces the following TAP
271
272 t/test.t ..
273 ok 1 - require Digest::MD5;
274 ok 2 - The object isa Digest::MD5
275 1..2
276 ok 1 - Testing Digest::MD5
277 ok 1 - require Digest::SHA1;
278 ok 2 - The object isa Digest::SHA1
279 1..2
280 ok 2 - Testing Digest::SHA1
281 1..2
282 ok
283 All tests successful.
284 Files=1, Tests=2, 0 wallclock secs ( 0.02 usr 0.01 sys + 0.06 cusr 0.00 csys = 0.09 CPU)
285 Result: PASS
286
287 run_me
288 run_me;
289 run_me( $description );
290 run_me( $init_args );
291 run_me( $description, $init_args );
292
293 The "run_me" function calls the "run_tests" method on the current
294 package and passes all arguments to that method. It takes a description
295 and/or a hash reference of constructor arguments.
296
297DIFFERENCES FROM TEST::ROUTINE
298 While this module was inspired by Test::Routine, it is not a drop-in
299 replacement. Here is an overview of major differences:
300
301 * Test::Roo uses Moo; Test::Routine uses Moose
302
303 * Loading Test::Roo makes the importing package a class; in
304 Test::Routine it becomes a role
305
306 * Loading Test::Roo loads Test::More; Test::Routine does not
307
308 * In Test::Roo, "run_test" is a method; in Test::Routine it is a
309 function and takes arguments in a different order
310
311 * In Test::Roo, all role composition must be explicit using "with"; in
312 Test::Routine, the "run_tests" command can also compose roles
313
314 * In Test::Roo, test blocks become method modifiers hooked on an empty
315 method; in Test::Routine, they become methods run via introspection
316
317 * In Test::Roo, setup and teardown are done by modifying "setup" and
318 "teardown" methods; in Test::Routine they are done by modifying
319 "run_test"
320
321SUPPORT
322 Bugs / Feature Requests
323 Please report any bugs or feature requests through the issue tracker at
324 <https://github.com/dagolden/Test-Roo/issues>. You will be notified
325 automatically of any progress on your issue.
326
327 Source Code
328 This is open source software. The code repository is available for
329 public review and contribution under the terms of the license.
330
331 <https://github.com/dagolden/Test-Roo>
332
333 git clone https://github.com/dagolden/Test-Roo.git
334
335AUTHOR
336 David Golden <dagolden@cpan.org>
337
338CONTRIBUTORS
339 * Arthur Axel 'fREW' Schmidt <frioux@gmail.com>
340
341 * Diab Jerius <djerius@gmail.com>
342
343COPYRIGHT AND LICENSE
344 This software is Copyright (c) 2013 by David Golden.
345
346 This is free software, licensed under:
347
348 The Apache License, Version 2.0, January 2004
349
350