File Coverage

blib/lib/Test/Class/Moose/Role/AutoUse.pm
Criterion Covered Total %
statement 29 30 96.6
branch 2 4 50.0
condition n/a
subroutine 9 9 100.0
pod 1 1 100.0
total 41 44 93.1


line stmt bran cond sub pod time code
1             package Test::Class::Moose::Role::AutoUse;
2              
3             # ABSTRACT: Automatically load the classes you're testing
4              
5 3     3   2568 use strict;
  3         8  
  3         68  
6 2     2   8 use warnings;
  2         5  
  2         40  
7 2     2   10 use namespace::autoclean;
  2         5  
  2         14  
8              
9 2     2   158 use 5.010000;
  2         5  
10              
11             our $VERSION = '0.97';
12              
13 2     2   10 use Moose::Role;
  2         13  
  2         18  
14 2     2   9384 use Carp 'confess';
  2         5  
  2         451  
15              
16             has 'class_name' => (
17             is => 'ro',
18             isa => 'Maybe[Str]',
19             builder => '_build_class_name',
20             );
21              
22             sub _build_class_name {
23 3     3   1467 my $test = shift;
24              
25 3 50       14 my $name = $test->get_class_name_to_use or return;
26              
27 2     2   361 eval "use $name";
  2         11124  
  2         46  
  3         211  
28 3 50       14 if ( my $error = $@ ) {
29 0         0 confess("Could not use $name: $error");
30             }
31 3         12 return $name;
32             }
33              
34             sub get_class_name_to_use {
35 3     3 1 7 my $test = shift;
36 3         6 my $name = ref $test;
37 3         17 $name =~ s/^[^:]+:://;
38 3         13 return $name;
39             }
40              
41             1;
42              
43             =pod
44              
45             =encoding UTF-8
46              
47             =head1 NAME
48              
49             Test::Class::Moose::Role::AutoUse - Automatically load the classes you're testing
50              
51             =head1 VERSION
52              
53             version 0.97
54              
55             =head1 SYNOPSIS
56              
57             package TestsFor::Some::Class;
58             use Test::Class::Moose;
59             with 'Test::Class::Moose::Role::AutoUse';
60              
61             sub test_constructor {
62             my $test = shift;
63              
64             my $class = $test->class_name; # Some::Class
65             can_ok $class, 'new'; # Some::Class is already loaded
66             isa_ok my $object = $class->new, $class; # and can be used as normal
67             }
68              
69             =head1 DESCRIPTION
70              
71             This role allows you to automatically C<use> the classes your test class is
72             testing, providing the name of the class via the C<class_name> attribute.
73             Thus, you don't need to hardcode your class names.
74              
75             =head1 PROVIDES
76              
77             =head2 C<class_name>
78              
79             Returns the name of the class you're testing. As a side-effect, the first time
80             it's called it will attempt to C<use> the class being tested.
81              
82             =head2 C<get_class_name_to_use>
83              
84             This method strips the leading section of the package name, up to and
85             including the first C<::>, and returns the rest of the name as the name of the
86             class being tested. For example, if your test class is named
87             C<Tests::Some::Person>, the name C<Some::Person> is returned as the name of
88             the class to use and test. If your test class is named
89             C<IHateTestingThis::Person>, then C<Person> is the name of the class to be
90             used and tested.
91              
92             If you don't like how the name is calculated, you can override this method in
93             your code.
94              
95             Warning: Don't use L<Test::> as a prefix. There are already plenty of modules
96             in that namespace and you could accidentally cause a collision.
97              
98             =head1 RATIONALE
99              
100             The example from our synopsis looks like this:
101              
102             package TestsFor::Some::Class;
103             use Test::Class::Moose;
104             with 'Test::Class::Moose::Role::AutoUse';
105              
106             sub test_constructor {
107             my $test = shift;
108              
109             my $class = $test->class_name; # Some::Class
110             can_ok $class, 'new'; # Some::Class is already loaded
111             isa_ok my $object = $class->new, $class; # and can be used as normal
112             }
113              
114             Without this role, it would often look like this:
115              
116             package TestsFor::Some::Class;
117             use Test::Class::Moose;
118             use Some::Class;
119              
120             sub test_constructor {
121             my $test = shift;
122              
123             can_ok 'Some::Class', 'new';
124             isa_ok my $object = 'Some::Class'->new, 'Some::Class';
125             }
126              
127             That's OK, but there are a couple of issues here.
128              
129             First, if you need to rename your class, you must change this name repeatedly.
130             With L<Test::Class::Moose::Role::AutoUse>, you only rename the test class name
131             to correspond to the new class name and you're done.
132              
133             The first problem is not very serious, but the second problem is. Let's say
134             you have a C<Person> class and then you create a C<Person::Employee> subclass.
135             Your test subclass might look like this:
136              
137             package TestsFor::Person::Employee;
138              
139             use Test::Class::Moose extends => "TestsFor::Person";
140              
141             # insert tests here
142              
143             Object-oriented tests I<inherit> their parent class tests. Thus,
144             C<TestsFor::Person::Employee> will inherit the
145             C<< TestsFor::Person->test_constructor() >> method. Except as you can see in our
146             example above, we've B<hardcoded> the class name, meaning that we won't be
147             testing our code appropriately. The code using the
148             L<Test::Class::Moose::Role::AutoUse> role doesn't hardcode the class name (at
149             least, it shouldn't), so when we call the inherited
150             C<< TestsFor::Person::Employee->test_constructor() >> method, it constructs a
151             C<TestsFor::Person::Employee> object, not a C<TestsFor::Person> object.
152              
153             Some might argue that this is a strawman and we should have done this:
154              
155             package TestsFor::Some::Class;
156             use Test::Class::Moose;
157             use Some::Class;
158              
159             sub class_name { 'Some::Class' }
160              
161             sub test_constructor {
162             my $test = shift;
163              
164             my $class = $test->class_name; # Some::Class
165             can_ok $class, 'new'; # Some::Class is already loaded
166             isa_ok my $object = $class->new, $class; # and can be used as normal
167             }
168              
169             Yes, that's correct. We should have done this, except that now it's almost
170             identical to the AutoUse code, except that the first time you forget to C<use>
171             the class in question, you'll be unhappy. Why not automate this?
172              
173             =head1 SUPPORT
174              
175             Bugs may be submitted at L<https://github.com/houseabsolute/test-class-moose/issues>.
176              
177             I am also usually active on IRC as 'autarch' on C<irc://irc.perl.org>.
178              
179             =head1 SOURCE
180              
181             The source code repository for Test-Class-Moose can be found at L<https://github.com/houseabsolute/test-class-moose>.
182              
183             =head1 AUTHORS
184              
185             =over 4
186              
187             =item *
188              
189             Curtis "Ovid" Poe <ovid@cpan.org>
190              
191             =item *
192              
193             Dave Rolsky <autarch@urth.org>
194              
195             =back
196              
197             =head1 COPYRIGHT AND LICENSE
198              
199             This software is copyright (c) 2012 - 2019 by Curtis "Ovid" Poe.
200              
201             This is free software; you can redistribute it and/or modify it under
202             the same terms as the Perl 5 programming language system itself.
203              
204             The full text of the license can be found in the
205             F<LICENSE> file included with this distribution.
206              
207             =cut
208              
209             __END__
210              
211              
212             1;