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   4968 use strict;
  2         9  
  2         56  
3 2     2   10 use warnings;
  2         5  
  2         63  
4              
5 2     2   9 use parent qw(Test::Class);
  2         3  
  2         32  
6              
7 2     2   169325 use Carp;
  2         4  
  2         109  
8 2     2   1094 use Test::MockObject::Extends;
  2         15178  
  2         9  
9 2     2   1123 use Test::MockModule;
  2         10714  
  2         15  
10 2     2   1366 use Test::Deep qw(cmp_deeply);
  2         21801  
  2         13  
11              
12             our $VERSION = '0.04';
13              
14             sub setup : Test(setup) {
15 2     2 0 2145 my $self = shift;
16              
17 2         8 my $module = $self->get_module_name();
18 2 100 66     18 if ( defined $module && $self->create_instance() ) {
19 1         12 my $instance = Test::MockObject::Extends->new($module);
20 1         741 $self->{instance} = $instance;
21             }
22 2         17 $self->_setup();
23 2         15 return;
24 2     2   585 }
  2         4  
  2         12  
25              
26             sub run_test_cases {
27 2     2 1 45 my ( $self, $cases ) = @_;
28              
29 2         8 foreach my $case ( @{$cases} ) {
  2         6  
30 8         21 my $hook = $case->{pre_test_hook};
31 8 100 66     24 if ( defined $hook && ref $hook eq 'CODE' ) {
32 1         3 &$hook();
33             }
34 8         17 my $method = $case->{method};
35 8         11 my $res;
36 8         19 my $instance = $self->get_instance();
37 8         37 my $module = $self->get_module_name();
38 8 100 66     50 if ( defined $instance
    50 66        
39             && $instance->can($method)
40             && !$self->run_on_module() )
41             {
42 5         9 $res = $instance->$method( @{ $case->{params} } );
  5         16  
43             }
44             elsif ( defined $module ) {
45 3         17 my $call = $module->can($method);
46 3 50       8 if ( defined $call ) {
47 3         3 $res = &$call( @{ $case->{params} } );
  3         10  
48             }
49             }
50              
51 8         47 my $exp = $case->{exp};
52 8 100 66     44 if ( defined $exp && ref $exp eq 'CODE' ) {
53 1         6 $res = &$exp($res);
54 1         7 $exp = 1;
55             }
56 8         28 cmp_deeply( $res, $exp, $case->{name} );
57              
58 8         3205 $hook = $case->{post_test_hook};
59 8 100 66     37 if ( defined $hook && ref $hook eq 'CODE' ) {
60 1         4 &$hook();
61             }
62             }
63 2         7 return;
64             }
65              
66             sub get_instance {
67 10     10 1 1697 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 1733 my ( $self, $set_value ) = @_;
86              
87 6 100       21 if ( defined $set_value ) {
88 1         11 $self->{_run_on_module} = $set_value;
89             }
90              
91 6   100     28 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.04
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