use strict; use warnings; package Test::Routine; # ABSTRACT: composable units of assertion $Test::Routine::VERSION = '0.024'; #pod =head1 SYNOPSIS #pod #pod # mytest.t #pod use Test::More; #pod use Test::Routine; #pod use Test::Routine::Util; #pod #pod has fixture => ( #pod is => 'ro', #pod lazy => 1, #pod clearer => 'reset_fixture', #pod default => sub { ...expensive setup... }, #pod ); #pod #pod test "we can use our fixture to do stuff" => sub { #pod my ($self) = @_; #pod #pod $self->reset_fixture; # this test requires a fresh one #pod #pod ok( $self->fixture->do_things, "do_things returns true"); #pod ok( ! $self->fixture->no_op, "no_op returns false"); #pod #pod for my $item ($self->fixture->contents) { #pod isa_ok($item, 'Fixture::Entry'); #pod } #pod }; #pod #pod test "fixture was recycled" => sub { #pod my ($self) = @_; #pod #pod my $fixture = $self->fixture; # we don't expect a fresh one #pod #pod is( $self->fixture->things_done, 1, "we have done one thing already"); #pod }; #pod #pod run_me; #pod done_testing; #pod #pod =head1 DESCRIPTION #pod #pod Test::Routine is a very simple framework for writing your tests as composable #pod units of assertion. In other words: roles. #pod #pod For a walkthrough of tests written with Test::Routine, see #pod L. #pod #pod Test::Routine is similar to L in some ways. These similarities #pod are largely superficial, but the idea of "tests bound together in reusable #pod units" is a useful one to understand when coming to Test::Routine. If you are #pod already familiar with Test::Class, it is the differences rather than the #pod similarities that will be more important to understand. If you are not #pod familiar with Test::Class, there is no need to understand it prior to using #pod Test::Routine. #pod #pod On the other hand, an understanding of the basics of L is absolutely #pod essential. Test::Routine composes tests from Moose classes, roles, and #pod attributes. Without an understanding of those, you will not be able to use #pod Test::Routine. The L is an excellent resource for learning #pod Moose, and has links to other online tutorials and documentation. #pod #pod =head2 The Concepts #pod #pod =head2 The Basics of Using Test::Routine #pod #pod There actually isn't much to Test::Routine I than the basics. It does #pod not provide many complex features, instead delegating almost everything to the #pod Moose object system. #pod #pod =head3 Writing Tests #pod #pod To write a set of tests (a test routine, which is a role), you add C to your package. C
is an acceptable target for turning #pod into a test routine, meaning that you may use Test::Routine in your F<*.t> #pod files in your distribution. #pod #pod C-ing Test::Routine will turn your package into a role that composes #pod L, and will give you the C declarator for adding #pod tests to your routine. Test::Routine::Common adds the C method that #pod will be called to run each test. #pod #pod The C declarator is very simple, and will generally be called like this: #pod #pod test $NAME_OF_TEST => sub { #pod my ($self) = @_; #pod #pod is($self->foo, 123, "we got the foo we expected"); #pod ... #pod ... #pod }; #pod #pod This defines a test with a given name, which will be invoked like a method on #pod the test object (described below). Tests are ordered by declaration within the #pod file, but when multiple test routines are run in a single test, the ordering of #pod the routines is B. #pod #pod C may also be given a different name for the installed method and the #pod test description. This isn't usually needed, but can make things clearer when #pod referring to tests as methods: #pod #pod test $NAME_OF_TEST_METHOD => { description => $TEST_DESCRIPTION } => sub { #pod ... #pod } #pod #pod Each test will be run by the C method. To add setup or teardown #pod behavior, advice (method modifiers) may be attached to that method. For #pod example, to call an attribute clearer before each test, you could add: #pod #pod before run_test => sub { #pod my ($self) = @_; #pod #pod $self->clear_some_attribute; #pod }; #pod #pod =head3 Running Tests #pod #pod To run tests, you will need to use L, which will provide #pod two functions for running tests: C and C. The former is #pod given a set of packages to compose and run as tests. The latter runs the #pod caller, assuming it to be a test routine. #pod #pod C can be called in several ways: #pod #pod run_tests( $desc, $object ); #pod #pod run_tests( $desc, \@packages, $arg ); #pod #pod run_tests( $desc, $package, $arg ); # equivalent to ($desc, [$pkg], $arg) #pod #pod In the first case, the object is assumed to be a fully formed, testable object. #pod In other words, you have already created a class that composes test routines #pod and have built an instance of it. #pod #pod In the other cases, C will produce an instance for you. It divides #pod the given packages into classes and roles. If more than one class was given, #pod an exception is thrown. A new class is created subclassing the given class and #pod applying the given roles. If no class was in the list, Moose::Object is used. #pod The new class's C is called with the given C<$arg> (if any). #pod #pod The composition mechanism makes it easy to run a test routine without first #pod writing a class to which to apply it. This is what makes it possible to write #pod your test routine in the C
package and run it directly from your F<*.t> #pod file. The following is a valid, trivial use of Test::Routine: #pod #pod use Test::More; #pod use Test::Routine; #pod use Test::Routine::Util; #pod #pod test demo_test => sub { pass("everything is okay") }; #pod #pod run_tests('our tests', 'main'); #pod done_testing; #pod #pod In this circumstance, though, you'd probably use C, which runs the #pod tests in the caller. You'd just replace the C line with #pod C<< run_me; >>. A description for the run may be supplied, if you like. #pod #pod Each call to C or C generates a new instance, and you can #pod call them as many times, with as many different arguments, as you like. Since #pod Test::Routine can't know how many times you'll call different test routines, #pod you are responsible for calling C> when #pod you're done testing. #pod #pod =head4 Running individual tests #pod #pod If you only want to run a subset of the tests, you can set the #pod C environment variable to a regular expression that matches #pod the names of the tests you want to run. #pod #pod For example, to run just the test named C in the #pod C class. #pod #pod use Test::More; #pod use Test::Routine::Util; #pod #pod $ENV{TEST_METHOD} = 'customer profile'; #pod run_tests('one test', 'MyTests'); #pod done_testing; #pod #pod To run all tests with C in the name: #pod #pod use Test::More; #pod use Test::Routine::Util; #pod #pod $ENV{TEST_METHOD}= '.*customer.*'; #pod run_tests('some tests', 'MyTests'); #pod done_testing; #pod #pod If you specify an invalid regular expression, your tests will not be #pod run: #pod #pod use Test::More; #pod use Test::Routine::Util #pod #pod $ENV{TEST_METHOD} = 'C++' #pod run_tests('invalid', 'MyTests'); #pod done_testing; #pod #pod When you run it: #pod #pod 1..0 #pod # No tests run! #pod not ok 1 - No tests run for subtest "invalid" #pod #pod =cut use Moose::Exporter; use Moose::Role (); use Moose::Util (); use Scalar::Util qw(blessed); use Test::Routine::Common; use Test::Routine::Test; Moose::Exporter->setup_import_methods( with_caller => [ qw(test) ], also => 'Moose::Role', ); sub init_meta { my ($class, %arg) = @_; my $meta = Moose::Role->init_meta(%arg); my $role = $arg{for_class}; Moose::Util::apply_all_roles($role, 'Test::Routine::Common'); return $meta; } my $i = 0; sub test { my $caller = shift; my $name = shift; my ($arg, $body); if (blessed($_[0]) && $_[0]->isa('Class::MOP::Method')) { $arg = {}; $body = shift; } else { $arg = Params::Util::_HASH0($_[0]) ? { %{shift()} } : {}; $body = shift; } # This could really have been done with a MooseX like InitArgs or Alias in # Test::Routine::Test, but since this is a test library, I'd actually like to # keep prerequisites fairly limited. -- rjbs, 2010-09-28 if (exists $arg->{desc}) { Carp::croak "can't supply both 'desc' and 'description'" if exists $arg->{description}; $arg->{description} = delete $arg->{desc}; } $arg->{description} = $name unless defined $arg->{description}; $name =~ s/(?:::|')/_/g; my $class = Moose::Meta::Class->initialize($caller); my %origin; @origin{qw(file line nth)} = ((caller(1))[1,2], $i++); my $method; if (blessed($body) && $body->isa('Class::MOP::Method')) { my $method_metaclass = Moose::Util::with_traits( blessed($body), 'Test::Routine::Test::Role' ); $method = $method_metaclass->meta->rebless_instance( $body, %$arg, name => $name, package_name => $caller, _origin => \%origin, ); } else { $method = Test::Routine::Test->wrap( %$arg, name => $name, body => $body, package_name => $caller, _origin => \%origin, ); } Carp::croak "can't have two tests with the same name ($name)" if $class->get_method($name); Carp::croak "there's already a subroutine named $name in $caller" if $caller->can($name); Carp::croak "can't name a test after a Moose::Object method ($name)" if Moose::Object->can($name); $class->add_method($name => $method); } 1; __END__ =pod =encoding UTF-8 =head1 NAME Test::Routine - composable units of assertion =head1 VERSION version 0.024 =head1 SYNOPSIS # mytest.t use Test::More; use Test::Routine; use Test::Routine::Util; has fixture => ( is => 'ro', lazy => 1, clearer => 'reset_fixture', default => sub { ...expensive setup... }, ); test "we can use our fixture to do stuff" => sub { my ($self) = @_; $self->reset_fixture; # this test requires a fresh one ok( $self->fixture->do_things, "do_things returns true"); ok( ! $self->fixture->no_op, "no_op returns false"); for my $item ($self->fixture->contents) { isa_ok($item, 'Fixture::Entry'); } }; test "fixture was recycled" => sub { my ($self) = @_; my $fixture = $self->fixture; # we don't expect a fresh one is( $self->fixture->things_done, 1, "we have done one thing already"); }; run_me; done_testing; =head1 DESCRIPTION Test::Routine is a very simple framework for writing your tests as composable units of assertion. In other words: roles. For a walkthrough of tests written with Test::Routine, see L. Test::Routine is similar to L in some ways. These similarities are largely superficial, but the idea of "tests bound together in reusable units" is a useful one to understand when coming to Test::Routine. If you are already familiar with Test::Class, it is the differences rather than the similarities that will be more important to understand. If you are not familiar with Test::Class, there is no need to understand it prior to using Test::Routine. On the other hand, an understanding of the basics of L is absolutely essential. Test::Routine composes tests from Moose classes, roles, and attributes. Without an understanding of those, you will not be able to use Test::Routine. The L is an excellent resource for learning Moose, and has links to other online tutorials and documentation. =head2 The Concepts =head2 The Basics of Using Test::Routine There actually isn't much to Test::Routine I than the basics. It does not provide many complex features, instead delegating almost everything to the Moose object system. =head3 Writing Tests To write a set of tests (a test routine, which is a role), you add C to your package. C
is an acceptable target for turning into a test routine, meaning that you may use Test::Routine in your F<*.t> files in your distribution. C-ing Test::Routine will turn your package into a role that composes L, and will give you the C declarator for adding tests to your routine. Test::Routine::Common adds the C method that will be called to run each test. The C declarator is very simple, and will generally be called like this: test $NAME_OF_TEST => sub { my ($self) = @_; is($self->foo, 123, "we got the foo we expected"); ... ... }; This defines a test with a given name, which will be invoked like a method on the test object (described below). Tests are ordered by declaration within the file, but when multiple test routines are run in a single test, the ordering of the routines is B. C may also be given a different name for the installed method and the test description. This isn't usually needed, but can make things clearer when referring to tests as methods: test $NAME_OF_TEST_METHOD => { description => $TEST_DESCRIPTION } => sub { ... } Each test will be run by the C method. To add setup or teardown behavior, advice (method modifiers) may be attached to that method. For example, to call an attribute clearer before each test, you could add: before run_test => sub { my ($self) = @_; $self->clear_some_attribute; }; =head3 Running Tests To run tests, you will need to use L, which will provide two functions for running tests: C and C. The former is given a set of packages to compose and run as tests. The latter runs the caller, assuming it to be a test routine. C can be called in several ways: run_tests( $desc, $object ); run_tests( $desc, \@packages, $arg ); run_tests( $desc, $package, $arg ); # equivalent to ($desc, [$pkg], $arg) In the first case, the object is assumed to be a fully formed, testable object. In other words, you have already created a class that composes test routines and have built an instance of it. In the other cases, C will produce an instance for you. It divides the given packages into classes and roles. If more than one class was given, an exception is thrown. A new class is created subclassing the given class and applying the given roles. If no class was in the list, Moose::Object is used. The new class's C is called with the given C<$arg> (if any). The composition mechanism makes it easy to run a test routine without first writing a class to which to apply it. This is what makes it possible to write your test routine in the C
package and run it directly from your F<*.t> file. The following is a valid, trivial use of Test::Routine: use Test::More; use Test::Routine; use Test::Routine::Util; test demo_test => sub { pass("everything is okay") }; run_tests('our tests', 'main'); done_testing; In this circumstance, though, you'd probably use C, which runs the tests in the caller. You'd just replace the C line with C<< run_me; >>. A description for the run may be supplied, if you like. Each call to C or C generates a new instance, and you can call them as many times, with as many different arguments, as you like. Since Test::Routine can't know how many times you'll call different test routines, you are responsible for calling C> when you're done testing. =head4 Running individual tests If you only want to run a subset of the tests, you can set the C environment variable to a regular expression that matches the names of the tests you want to run. For example, to run just the test named C in the C class. use Test::More; use Test::Routine::Util; $ENV{TEST_METHOD} = 'customer profile'; run_tests('one test', 'MyTests'); done_testing; To run all tests with C in the name: use Test::More; use Test::Routine::Util; $ENV{TEST_METHOD}= '.*customer.*'; run_tests('some tests', 'MyTests'); done_testing; If you specify an invalid regular expression, your tests will not be run: use Test::More; use Test::Routine::Util $ENV{TEST_METHOD} = 'C++' run_tests('invalid', 'MyTests'); done_testing; When you run it: 1..0 # No tests run! not ok 1 - No tests run for subtest "invalid" =head1 AUTHOR Ricardo Signes =head1 CONTRIBUTORS =for stopwords Alex White Dagfinn Ilmari Mannsåker gregor herrmann Jesse Luehrs Yanick Champoux =over 4 =item * Alex White =item * Dagfinn Ilmari Mannsåker =item * gregor herrmann =item * Jesse Luehrs =item * Yanick Champoux =back =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2010 by Ricardo Signes. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut