File Coverage

lib/Test/Class/Simple.pm
Criterion Covered Total %
statement 64 66 96.9
branch 14 16 87.5
condition 14 20 70.0
subroutine 13 15 86.6
pod 5 6 83.3
total 110 123 89.4


line stmt bran cond sub pod time code
1             package Test::Class::Simple;
2 2     2   4695 use strict;
  2         10  
  2         55  
3 2     2   10 use warnings;
  2         4  
  2         52  
4              
5 2     2   9 use parent qw(Test::Class);
  2         3  
  2         22  
6              
7 2     2   167791 use Carp;
  2         5  
  2         108  
8 2     2   1115 use Test::MockObject::Extends;
  2         15246  
  2         7  
9 2     2   1120 use Test::MockModule;
  2         10571  
  2         14  
10 2     2   1426 use Test::Deep qw(cmp_deeply);
  2         21730  
  2         14  
11              
12             our $VERSION = '0.05';
13              
14             sub setup : Test(setup) {
15 2     2 0 2197 my $self = shift;
16              
17 2         12 my $module = $self->get_module_name();
18 2 100 66     22 if ( defined $module && $self->create_instance() ) {
19 1         16 my $instance = Test::MockObject::Extends->new($module);
20 1         765 $self->{instance} = $instance;
21             }
22 2         31 $self->_setup();
23 2         17 return;
24 2     2   637 }
  2         6  
  2         14  
25              
26             sub run_test_cases {
27 2     2 1 48 my ( $self, $cases ) = @_;
28              
29 2         9 foreach my $case ( @{$cases} ) {
  2         6  
30 8         19 my $hook = $case->{pre_test_hook};
31 8 100 66     32 if ( defined $hook && ref $hook eq 'CODE' ) {
32 1         4 &$hook();
33             }
34 8         15 my $method = $case->{method};
35 8         13 my $res;
36 8         21 my $instance = $self->get_instance();
37 8         57 my $module = $self->get_module_name();
38 8 100 66     55 if ( defined $instance
    50 66        
39             && $instance->can($method)
40             && !$self->run_on_module() )
41             {
42 5         7 $res = $instance->$method( @{ $case->{params} } );
  5         17  
43             }
44             elsif ( defined $module ) {
45 3         20 my $call = $module->can($method);
46 3 50       8 if ( defined $call ) {
47 3         4 $res = &$call( @{ $case->{params} } );
  3         11  
48             }
49             }
50              
51 8         48 my $exp = $case->{exp};
52 8 100 66     35 if ( defined $exp && ref $exp eq 'CODE' ) {
53 1         4 $res = &$exp($res);
54 1         7 $exp = 1;
55             }
56 8         40 cmp_deeply( $res, $exp, $case->{name} );
57              
58 8         3201 $hook = $case->{post_test_hook};
59 8 100 66     38 if ( defined $hook && ref $hook eq 'CODE' ) {
60 1         5 &$hook();
61             }
62             }
63 2         8 return;
64             }
65              
66             sub get_instance {
67 10     10 1 1734 my $self = shift;
68              
69 10         20 return $self->{instance};
70             }
71              
72             sub get_module_name {
73 0     0 1 0 croak('Module name should be set');
74             }
75              
76             sub create_instance {
77 0     0 1 0 return 0;
78             }
79              
80             sub _setup {
81 1     1   2 return;
82             }
83              
84             sub run_on_module {
85 6     6 1 1858 my ( $self, $set_value ) = @_;
86              
87 6 100       19 if ( defined $set_value ) {
88 1         14 $self->{_run_on_module} = $set_value;
89             }
90              
91 6   100     31 return $self->{_run_on_module} // 0;
92             }
93              
94             1;
95              
96             =head1 NAME
97              
98             Test::Class::Simple - Simplify your unit tests writing based on Test::Class
99              
100             =head1 VERSION
101              
102             version 0.05
103              
104             =head1 SYNOPSIS
105              
106             package My::Example;
107              
108             sub new {
109             my $class = shift;
110              
111             $class = ref($class) || $class;
112             my $self = { _counter => 0 };
113             bless $self, $class;
114             return $self;
115             }
116              
117             sub increase_counter {
118             my $self = shift;
119              
120             $self->{_counter}++;
121             return $self->{_counter};
122             }
123              
124              
125             package My::Example::Test;
126             use parent qw(Test::Class::Simple);
127              
128             # setup methods are run before every test method.
129             sub _setup {
130             my $self = shift;
131              
132             # get mocked object of the class that is Test::MockObject::Extends
133             my $instance = $self->get_instance();
134             $instance->{_counter} = 100;
135             return;
136             }
137              
138             # Set which class should be mocked
139             sub get_module_name {
140             return 'My::Example';
141             }
142              
143             # Indicate that instance should be created
144             sub create_instance {
145             return 1;
146             }
147              
148             # a test method that runs 2 test cases
149             sub test_counter : Test(2) {
150             my $self = shift;
151              
152             my $test_cases = [
153             {
154             method => 'increase_counter',
155             params => [],
156             exp => 101,
157             name => 'Increase counter once',
158             },
159             {
160             method => 'increase_counter',
161             params => [],
162             exp => 102,
163             name => 'Increase counter twice',
164             },
165             ];
166             $self->run_test_cases($test_cases);
167             return;
168             }
169              
170             later in a nearby .t file
171              
172             #!/usr/bin/perl
173             use My::Example::Test;
174              
175             # run all the test methods in My::Example::Test
176             My::Example::Test->new()->runtests();
177             exit 0;
178              
179             =head1 DESCRIPTION
180              
181             This is an extension of L module to implement unit tests in more simple and declarative way.
182              
183             =head2 Methods
184              
185             =head3 _setup()
186              
187             Method that is executed before every test method and is useful for some initializations required for the tests.
188              
189             =head3 get_instance()
190              
191             Returns mocked object of the class specified in L. If L
192             is set to false, returns C value.
193              
194             =head3 create_instance()
195              
196             Can be overridden and must return boolean value. Indicates whether mocked instance should be created.
197              
198             =head3 get_module_name()
199              
200             Must be overridden and should return name of the module for which tests should be run.
201              
202             =head3 run_on_module($set_value)
203              
204             Sets boolean value that indicates that tests should run against the module rather then the instance of the class.
205              
206             =head3 run_test_cases($cases)
207              
208             Accepts arrayref of the test cases described with L inside hash references and executes them one by one.
209              
210             =head2 Options
211              
212             =head3 method
213              
214             Name of the method that should be executed.
215              
216             =head3 params
217              
218             Array reference of the parameters that should be passed to the L
219              
220             =head3 exp
221              
222             Can be either data structure or a code reference. For data structure L
223             will be executed. If code reference is set then result will be passed as a single parameter and will be expected to return
224             true value if test case was considered as successful.
225              
226             =head3 name
227              
228             Name of the test case. Usually shown in the output of test run.
229              
230             =head3 pre_test_hook
231              
232             Code reference that will be executed before current test case. E.g. for mocking data for next test case.
233              
234             =head3 post_test_hook
235              
236             Code reference that will be executed after current test case. E.g. for unmocking data.
237              
238             =head1 AUTHOR
239              
240             Oleksii Kysil
241              
242             =head1 COPYRIGHT & LICENSE
243              
244             Copyright 2020 Oleksii Kysil, all rights reserved.
245              
246             This program is free software; you can redistribute it and/or modify it
247             under the same terms as Perl itself.
248              
249             =cut