File Coverage

lib/Test/Class/Simple.pm
Criterion Covered Total %
statement 67 68 98.5
branch 16 16 100.0
condition 20 20 100.0
subroutine 15 16 93.7
pod 7 8 87.5
total 125 128 97.6


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