File Coverage

blib/lib/Test/LectroTest.pm
Criterion Covered Total %
statement 27 27 100.0
branch 2 4 50.0
condition n/a
subroutine 8 8 100.0
pod n/a
total 37 39 94.8


line stmt bran cond sub pod time code
1             package Test::LectroTest;
2             {
3             $Test::LectroTest::VERSION = '0.5001';
4             }
5              
6 2     2   8373 use warnings;
  2         5  
  2         87  
7 2     2   12 use strict;
  2         4  
  2         74  
8              
9 2     2   1530 use Test::LectroTest::TestRunner;
  2         9  
  2         69  
10 2     2   13 use Filter::Util::Call;
  2         4  
  2         737  
11             require Test::LectroTest::Property;
12             require Test::LectroTest::Generator;
13              
14             =head1 NAME
15              
16             Test::LectroTest - Easy, automatic, specification-based tests
17              
18             =head1 VERSION
19              
20             version 0.5001
21              
22             =head1 SYNOPSIS
23              
24             #!/usr/bin/perl -w
25              
26             use MyModule; # contains code we want to test
27             use Test::LectroTest;
28              
29             Property {
30             ##[ x <- Int, y <- Int ]##
31             MyModule::my_function( $x, $y ) >= 0;
32             }, name => "my_function output is non-negative" ;
33              
34             Property { ... }, name => "yet another property" ;
35              
36             # more properties to check here
37              
38             =head1 DESCRIPTION
39              
40             This module provides a simple (yet full featured) interface to
41             LectroTest, an automated, specification-based testing system for Perl.
42             To use it, declare properties that specify the expected behavior
43             of your software. LectroTest then checks your software to see whether
44             those properties hold.
45              
46             Declare properties using the C function, which takes a
47             block of code and promotes it to a L:
48              
49             Property {
50             ##[ x <- Int, y <- Int ]##
51             MyModule::my_function( $x, $y ) >= 0;
52             }, name => "my_function output is non-negative" ;
53              
54             The first part of the block must contain a generator-binding
55             declaration. For example:
56              
57             ##[ x <- Int, y <- Int ]##
58              
59             (Note the special bracketing, which is required.) This particular
60             binding says, "For all integers I and I." (By the way, you
61             aren't limited to integers. LectroTest also gives you booleans,
62             strings, lists, hashes, and more, and it lets you define your own
63             generator types. See L for more.)
64              
65             The second part of the block is simply a snippet of code that makes
66             use of the variables we bound earlier to test whether a property holds
67             for the piece of software we are testing:
68              
69             MyModule::my_function( $x, $y ) >= 0;
70              
71             In this case, it asserts that C returns
72             a non-negative result. (Yes, C<$x> and C<$y> refer to the same I
73             and I that we bound to the generators earlier. LectroTest
74             automagically loads these lexically bound Perl variables with values
75             behind the scenes.)
76              
77             B If you want to use testing assertions like C from
78             L or C, C, or C from L
79             (and the related family of L-based testing modules),
80             see L, which lets you mix and match
81             LectroTest with these modules.
82              
83             Finally, we give the whole Property a name, in this case "my_function
84             output is non-negative." It's a good idea to use a meaningful name
85             because LectroTest refers to properties by name in its output.
86              
87             Let's take a look at the finished property specification:
88              
89             Property {
90             ##[ x <- Int, y <- Int ]##
91             MyModule::my_function( $x, $y ) >= 0;
92             }, name => "my_function output is non-negative" ;
93              
94             It says, "For all integers I and I, we assert that my_function's
95             output is non-negative."
96              
97             To check whether this property holds, simply put it in a Perl program
98             that uses the Test::LectroTest module. (See the L for an
99             example.) When you run the program, LectroTest will load the property
100             (and any others in the file) and check it by running random trials
101             against the software you're testing.
102              
103             B If you want to place LectroTest property checks into
104             a test plan managed by L-based modules such as
105             L or L, see L.
106              
107             If LectroTest is able to "break" your software during the property
108             check, it will emit a counterexample to your property's assertions and
109             stop. You can plug the counterexample back into your software to
110             debug the problem. (You might also want to add the counterexample to
111             a list of regression tests.)
112              
113             A successful LectroTest looks like this:
114              
115             1..1
116             ok 1 - 'my_function output is non-negative' (1000 attempts)
117              
118             On the other hand, if you're not so lucky:
119              
120             1..1
121             not ok 1 - 'my_function output is non-negative' falsified \
122             in 324 attempts
123             # Counterexample:
124             # $x = -34
125             # $y = 0
126              
127             =head1 EXIT CODE
128              
129             The exit code returned by running a suite of property checks is the
130             number of failed checks. The code is 0 if all properties passed their
131             checks or I if I properties failed. (If more than 254 properties
132             failed, the exit code will be 254.)
133              
134              
135             =head1 ADJUSTING THE TESTING PARAMETERS
136              
137             There is one testing parameter (among others) that you might wish to
138             change from time to time: the number of trials to run for each
139             property checked. By default it is 1,000. If you want to try more or
140             fewer trials, pass the C>I flag:
141              
142             use Test::LectroTest trials => 10_000;
143              
144              
145             =head1 TESTING FOR REGRESSIONS AND CORNER CASES
146              
147             LectroTest can record failure-causing test cases to a file, and it can
148             play those test cases back as part of its normal testing strategy.
149             The easiest way to take advantage of this feature is to set the
150             I parameter when you C this module:
151              
152             use Test::LectroTest
153             regressions => "regressions.txt";
154              
155             This tells LectroTest to use the file "regressions.txt" for both
156             recording and playing back failures. If you want to record and
157             play back from separate files, or want only to record I play
158             back, use the I and/or
159             I options:
160              
161             use Test::LectroTest
162             playback_failures => "regression_suite_for_my_module.txt",
163             record_failures => "failures_in_the_field.txt";
164              
165             See L for more.
166              
167              
168             =head1 CAVEATS
169              
170             When you use this module, it imports all of the generator-building
171             functions from L into the your code's
172             namespace. This is almost always what you want, but I figured I ought
173             to say something about it here to reduce the possibility of surprise.
174              
175             A Property specification must appear in the first column, i.e.,
176             without any indentation, in order for it to be automatically loaded
177             and checked. If this poses a problem, let me know, and this
178             restriction can be lifted.
179              
180             =cut
181              
182             our $r;
183             our @props;
184             our @opts;
185              
186             sub import {
187 2     2   18 my $self = shift;
188 2         128 Test::LectroTest::Property->export_to_level(1, $self);
189 2         489 Test::LectroTest::Generator->export_to_level(1, $self, ':all');
190 2         6 @opts = @_;
191 2         11 $r = Test::LectroTest::TestRunner->new( @_ );
192 2         6 my $lines = 0;
193 2         8 my $subfilter = Test::LectroTest::Property::_make_code_filter();
194             filter_add( sub {
195 120     120   438 my $status = filter_read();
196 120         243 s{^(?=Test|Property)\b}{push \@Test::LectroTest::props, };
197 120         273 $subfilter->( $status );
198 2         13 });
199             }
200              
201             sub _run {
202 2     2   17 return @props - $r->run_suite( @props, @opts );
203             }
204              
205             END {
206 2 50   2   133 if ($r) {
207 2         19 my $failed = Test::LectroTest::_run();
208 2 50       0 $? = $failed > 254 ? 254 : $failed;
209             }
210             }
211              
212             1;
213              
214             __END__