1Test::LectroTest::TestRUusnenrerC(o3n)tributed Perl DocuTmeesntt:a:tLieocntroTest::TestRunner(3)
2
3
4
6 Test::LectroTest::TestRunner - Configurable TAP-compatible engine for
7 running LectroTest property checks
8
10 version 0.5001
11
13 use Test::LectroTest::TestRunner;
14
15 my @args = trials => 1_000, retries => 20_000;
16 my $runner = Test::LectroTest::TestRunner->new( @args );
17
18 # test a single property and print details upon failure
19 my $result = $runner->run( $a_single_lectrotest_property );
20 print $result->details unless $result->success;
21
22 # test a suite of properties, w/ Test::Harness::TAP output
23 my $num_successful = $runner->run_suite( @properties );
24 print "# All passed!" if $num_successful == @properties;
25
27 STOP! If you just want to write and run simple tests, see
28 Test::LectroTest. If you really want to learn about the property-
29 checking apparatus or turn its control knobs, read on.
30
31 This module provides Test::LectroTest::TestRunner, a class of objects
32 that tests properties by running repeated random trials. Create a
33 TestRunner, configure it, and then call its "run" or "run_suite"
34 methods to test properties individually or in groups.
35
37 The following methods are available.
38
39 new(named-params)
40 my $runner = new Test::LectroTest::TestRunner(
41 trials => 1_000,
42 retries => 20_000,
43 scalefn => sub { $_[0] / 2 + 1 },
44 verbose => 1,
45 regressions => "/path/to/regression_suite.txt",
46 );
47
48 Creates a new Test::LectroTest::TestRunner and configures it with the
49 given named parameters, if any. Typically, you need only provide the
50 "trials" parameter because the other values are reasonable for almost
51 all situations. Here is what each parameter means:
52
53 trials
54 The number of trials to run against each property checked. The
55 default is 1_000.
56
57 retries
58 The number of times to allow a property to retry trials (via
59 "$tcon->retry") during the entire property check before aborting
60 the check. This is used to prevent infinite looping, should the
61 property retry every attempt.
62
63 scalefn
64 A subroutine that scales the sizing guidance given to input
65 generators.
66
67 The TestRunner starts with an initial guidance of 1 at the
68 beginning of a property check. For each trial (or retry) of the
69 property, the guidance value is incremented. This causes
70 successive trials to be tried using successively more complex
71 inputs. The "scalefn" subroutine gets to adjust this guidance on
72 the way to the input generators. Typically, you would change the
73 "scalefn" subroutine if you wanted to change the rate and which
74 inputs grow during the course of the trials.
75
76 verbose
77 If this paramter is set to true (the default) the TestRunner will
78 use verbose output that includes things like label frequencies and
79 counterexamples. Otherwise, only one-line summaries will be
80 output. Unless you have a good reason to do otherwise, leave this
81 parameter alone because verbose output is almost always what you
82 want.
83
84 record_failures
85 If this parameter is set to a file's pathname (or a FailureRecorder
86 object), the TestRunner will record property-check failures to the
87 file (or recorder). (This is an easy way to build a regression-
88 testing suite.) If the file cannot be created or written to, this
89 parameter will be ignored. Set this parameter to "undef" (the
90 default) to turn off recording.
91
92 playback_failures
93 If this parameter is set to a file's pathname (or a FailureRecorder
94 object), the TestRunner will load previously recorded failures from
95 the file (or recorder) and use them as additional test cases when
96 checking properties. If the file cannot be read, this option will
97 be ignored. Set this parameter to "undef" (the default) to turn
98 off recording.
99
100 regressions
101 If this parameter is set to a file's pathname (or a FailureRecorder
102 object), the TestRunner will load failures from and record failures
103 to the file (or recorder). Setting this parameter is a shortcut
104 for, and exactly equivalent to, setting record_failures and
105 <playback_failures> to the same value, which is typically what you
106 want when managing a persistent suite of regression tests.
107
108 This is a write-only accessor.
109
110 You can also set and get the values of the configuration properties
111 using accessors of the same name. For example:
112
113 $runner->trials( 10_000 );
114
115 run(property)
116 $results = $runner->run( $a_property );
117 print $results->summary, "\n";
118 if ($results->success) {
119 # celebrate!
120 }
121
122 Checks whether the given property holds by running repeated random
123 trials. The result is a Test::LectroTest::TestRunner::results object,
124 which you can query for fined-grained information about the outcome of
125 the check.
126
127 The "run" method takes an optional second argument which gives the test
128 number. If it is not provided (usually the case), the next number
129 available from the TestRunner's internal counter is used.
130
131 $results = $runner->run( $third_property, 3 );
132
133 Additionally, if the TestRunner's playback_failures parameter is
134 defined, this method will play back any relevant failure cases from the
135 given playback file (or FailureRecorder).
136
137 Additionally, if the TestRunner's record_failures parameter is defined,
138 this method will record any new failures to the given file (or
139 FailureRecorder).
140
141 run_suite(properties...)
142 my $num_successful = $runner->run_suite( @properties );
143 if ($num_successful == @properties) {
144 # celebrate most jubilantly!
145 }
146
147 Checks a suite of properties, sending the results of each property
148 checked to "STDOUT" in a form that is compatible with
149 Test::Harness::TAP. For example:
150
151 1..5
152 ok 1 - Property->new disallows use of 'tcon' in bindings
153 ok 2 - magic Property syntax disallows use of 'tcon' in bindings
154 ok 3 - exceptions are caught and reported as failures
155 ok 4 - pre-flight check catches new w/ no args
156 ok 5 - pre-flight check catches unbalanced arguments list
157
158 By default, labeling statistics and counterexamples (if any) are
159 included in the output if the TestRunner's "verbose" property is true.
160 You may override the default by passing the "verbose" named parameter
161 after all of the properties in the argument list:
162
163 my $num_successes = $runner->run_suite( @properties,
164 verbose => 1 );
165 my $num_failed = @properties - $num_successes;
166
168 There are two kinds of objects that TestRunner uses as helpers.
169 Neither is meant to be created by you. Rather, a TestRunner will
170 create them on your behalf when they are needed.
171
172 The objects are described in the following subsections.
173
174 Test::LectroTest::TestRunner::results
175 my $results = $runner->run( $a_property );
176 print "Property name: ", $results->name, ": ";
177 print $results->success ? "Winner!" : "Loser!";
178
179 This is the object that you get back from "run". It contains all of
180 the information available about the outcome of a property check and
181 provides the following methods:
182
183 success
184 Boolean value: True if the property checked out successfully;
185 false otherwise.
186
187 summary
188 Returns a one line summary of the property-check outcome. It does
189 not end with a newline. Example:
190
191 ok 1 - Property->new disallows use of 'tcon' in bindings
192
193 details
194 Returns all relevant information about the property-check outcome
195 as a series of lines. The last line is terminated with a newline.
196 The details are identical to the summary (except for the
197 terminating newline) unless label frequencies are present or a
198 counterexample is present, in which case the details will have
199 these extras (the summary does not). Example:
200
201 1..1
202 not ok 1 - 'my_sqrt meets defn of sqrt' falsified in 1 attempts
203 # Counterexample:
204 # $x = '0.546384454460178';
205
206 name
207 Returns the name of the property to which the results pertain.
208
209 number
210 The number assigned to the property that was checked.
211
212 counterexample
213 Returns the counterexample that "broke" the code being tested, if
214 there is one. Otherwise, returns an empty string. If any notes
215 have been attached to the failing trial, they will be included.
216
217 labels
218 Label counts. If any labels were applied to trials during the
219 property check, this value will be a reference to a hash mapping
220 each combination of labels to the count of trials that had that
221 particular combination. Otherwise, it will be undefined.
222
223 Note that each trial is counted only once -- for the most-specific
224 combination of labels that was applied to it. For example,
225 consider the following labeling logic:
226
227 Property {
228 ##[ x <- Int ]##
229 $tcon->label("negative") if $x < 0;
230 $tcon->label("odd") if $x % 2;
231 1;
232 }, name => "negative/odd labeling example";
233
234 For a particular trial, if x was 2 (positive and even), the trial
235 would receive no labels. If x was 3 (positive and odd), the trial
236 would be labeled "odd". If x was -2 (negative and even), the trial
237 would be labeled "negative". If x was -3 (negative and odd), the
238 trial would be labeled "negative & odd".
239
240 label_frequencies
241 Returns a string containing a line-by-line accounting of labels
242 applied during the series of trials:
243
244 print $results->label_frequencies;
245
246 The corresponding output looks like this:
247
248 25% negative
249 25% negative & odd
250 25% odd
251
252 If no labels were applied, an empty string is returned.
253
254 exception
255 Returns the text of the exception or error that caused the series
256 of trials to be aborted, if the trials were aborted because an
257 exception or error was intercepted by LectroTest. Otherwise,
258 returns an empty string.
259
260 attempts
261 Returns the count of trials performed.
262
263 incomplete
264 In the event that the series of trials was halted before it was
265 completed (such as when the retry count was exhausted), this method
266 will return the reason. Otherwise, it returns an empty string.
267
268 Note that a series of trials is complete if a counterexample was
269 found.
270
271 Test::LectroTest::TestRunner::testcontroller
272 During a live property-check trial, the variable $tcon is available to
273 your Properties. It lets you label the current trial or request that
274 it be re-tried with new inputs.
275
276 The following methods are available.
277
278 retry
279 Property {
280 ##[ x <- Int ]##
281 return $tcon->retry if $x == 0;
282 }, ... ;
283
284 Stops the current trial and tells the TestRunner to re-try it with
285 new inputs. Typically used to reject a particular case of inputs
286 that doesn't make for a good or valid test. While not required,
287 you will probably want to call "$tcon->retry" as part of a "return"
288 statement to prevent further execution of your property's logic,
289 the results of which will be thrown out should it run to
290 completion.
291
292 The return value of "$tcon->retry" is itself meaningless; it is the
293 side-effect of calling it that causes the current trial to be
294 thrown out and re-tried.
295
296 label(string)
297 Property {
298 ##[ x <- Int ]##
299 $tcon->label("negative") if $x < 0;
300 $tcon->label("odd") if $x % 2;
301 }, ... ;
302
303 Applies a label to the current trial. At the end of the trial, all
304 of the labels are gathered together, and the trial is dropped into
305 a bucket bearing the combined label. See the discussion of
306 "labels" for more.
307
308 trivial
309 Property {
310 ##[ x <- Int ]##
311 $tcon->trivial if $x == 0;
312 }, ... ;
313
314 Applies the label "trivial" to the current trial. It is identical
315 to calling "label" with "trivial" as the argument.
316
317 note(string...)
318 Property {
319 ##[ s <- String( charset=>"A-Za-z0-9" ) ]##
320 my $s_enc = encode($s);
321 my $s_enc_dec = decode($s_enc);
322 $tcon->note("s_enc = $s_enc",
323 "s_enc_dec = $s_enc_dec");
324 $s eq $s_enc_dec;
325 }, name => "decode is encode's inverse" ;
326
327 Adds a note (or notes) to the current trial. In the event that the
328 trial fails, these notes will be emitted as part of the
329 counterexample. For example:
330
331 1..1
332 not ok 1 - property 'decode is encode's inverse' \
333 falsified in 68 attempts
334 # Counterexample:
335 # $s = "0";
336 # Notes:
337 # $s_enc = "";
338 # $s_enc_dec = "";
339
340 Notes can help you debug your code when something goes wrong. Use
341 them as debugging hints to yourself. For example, you can use
342 notes to record the output of each stage of a multi-stage test.
343 That way, if the test fails, you can see what happened in each
344 stage without having to plug the counterexample into your code
345 under a debugger.
346
347 If you want to include complicated values or data structures in
348 your notes, see the "dump" method, next, which may be more
349 appropriate.
350
351 dump(value, name)
352 Property {
353 ##[ s <- String ]##
354 my $s_enc = encode($s);
355 my $s_enc_dec = decode($s_enc);
356 $tcon->dump($s_enc, "s_enc");
357 $tcon->dump($s_enc_dec, "s_enc_dec");
358 $s eq $s_enc_dec;
359 }, name => "decode is encode's inverse" ;
360
361 Adds a note to the current trial in which the given value is
362 dumped. The value will be dumped via Data::Dumper and thus may be
363 complex and contain weird control characters and so on. If you
364 supply a name, it will be used to name the dumped value. Returns
365 value as its result.
366
367 In the event that the trial fails, the note (and any others) will
368 be emitted as part of the counterexample.
369
370 See "note" above for more.
371
373 Test::LectroTest::Property explains in detail what you can put inside
374 of your property specifications.
375
376 Test::LectroTest::RegressionTesting explains how to test for
377 regressions and corner cases using LectroTest.
378
379 Test::Harness:TAP documents the Test Anything Protocol, Perl's simple
380 text-based interface between testing modules such as Test::LectroTest
381 and the test harness Test::Harness.
382
384 Tom Moertel (tom@moertel.com)
385
387 The LectroTest project was inspired by Haskell's QuickCheck module by
388 Koen Claessen and John Hughes:
389 http://www.cs.chalmers.se/~rjmh/QuickCheck/.
390
392 Copyright (c) 2004-13 by Thomas G Moertel. All rights reserved.
393
394 This program is free software; you can redistribute it and/or modify it
395 under the same terms as Perl itself.
396
397
398
399perl v5.38.0 2023-07-21 Test::LectroTest::TestRunner(3)