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   5408 use strict;
  3         9  
  3         134  
6 2     2   14 use warnings;
  2         4  
  2         55  
7 2     2   10 use namespace::autoclean;
  2         4  
  2         12  
8              
9 2     2   182 use 5.010000;
  2         8  
10              
11             our $VERSION = '0.99';
12              
13 2     2   12 use Moose::Role;
  2         14  
  2         22  
14 2     2   11526 use Carp 'confess';
  2         6  
  2         577  
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   1863 my $test = shift;
24              
25 3 50       14 my $name = $test->get_class_name_to_use or return;
26              
27             ## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval)
28 2     2   490 eval "use $name";
  2         21282  
  2         50  
  3         282  
29 3 50       17 if ( my $error = $@ ) {
30 0         0 confess("Could not use $name: $error");
31             }
32 3         16 return $name;
33             }
34              
35             sub get_class_name_to_use {
36 3     3 1 7 my $test = shift;
37 3         9 my $name = ref $test;
38 3         18 $name =~ s/^[^:]+:://;
39 3         16 return $name;
40             }
41              
42             1;
43              
44             =pod
45              
46             =encoding UTF-8
47              
48             =head1 NAME
49              
50             Test::Class::Moose::Role::AutoUse - Automatically load the classes you're testing
51              
52             =head1 VERSION
53              
54             version 0.99
55              
56             =head1 SYNOPSIS
57              
58             package TestsFor::Some::Class;
59             use Test::Class::Moose;
60             with 'Test::Class::Moose::Role::AutoUse';
61              
62             sub test_constructor {
63             my $test = shift;
64              
65             my $class = $test->class_name; # Some::Class
66             can_ok $class, 'new'; # Some::Class is already loaded
67             isa_ok my $object = $class->new, $class; # and can be used as normal
68             }
69              
70             =head1 DESCRIPTION
71              
72             This role allows you to automatically C<use> the classes your test class is
73             testing, providing the name of the class via the C<class_name> attribute. Thus,
74             you don't need to hardcode your class names.
75              
76             =head1 PROVIDES
77              
78             =head2 C<class_name>
79              
80             Returns the name of the class you're testing. As a side-effect, the first time
81             it's called it will attempt to C<use> the class being tested.
82              
83             =head2 C<get_class_name_to_use>
84              
85             This method strips the leading section of the package name, up to and including
86             the first C<::>, and returns the rest of the name as the name of the class
87             being tested. For example, if your test class is named C<Tests::Some::Person>,
88             the name C<Some::Person> is returned as the name of the class to use and test.
89             If your test class is named C<IHateTestingThis::Person>, then C<Person> is the
90             name of the class to be 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 you
134             have a C<Person> class and then you create a C<Person::Employee> subclass. Your
135             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 C<<
145             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 C<<
150             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 - 2021 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;