1Test::MockRandom(3) User Contributed Perl Documentation Test::MockRandom(3)
2
3
4
6 Test::MockRandom - Replaces random number generation with non-random
7 number generation
8
10 version 1.01
11
13 # intercept rand in another package
14 use Test::MockRandom 'Some::Other::Package';
15 use Some::Other::Package; # exports sub foo { return rand }
16 srand(0.13);
17 foo(); # returns 0.13
18
19 # using a seed list and "oneish"
20 srand(0.23, 0.34, oneish() );
21 foo(); # returns 0.23
22 foo(); # returns 0.34
23 foo(); # returns a number just barely less than one
24 foo(); # returns 0, as the seed array is empty
25
26 # object-oriented, for use in the current package
27 use Test::MockRandom ();
28 my $nrng = Test::MockRandom->new(0.42, 0.23);
29 $nrng->rand(); # returns 0.42
30
32 This perhaps ridiculous-seeming module was created to test routines
33 that manipulate random numbers by providing a known output from "rand".
34 Given a list of seeds with "srand", it will return each in turn. After
35 seeded random numbers are exhausted, it will always return 0. Seed
36 numbers must be of a form that meets the expected output from "rand" as
37 called with no arguments -- i.e. they must be between 0 (inclusive)
38 and 1 (exclusive). In order to facilitate generating and testing a
39 nearly-one number, this module exports the function "oneish", which
40 returns a number just fractionally less than one.
41
42 Depending on how this module is called with "use", it will export
43 "rand" to a specified package (e.g. a class being tested) effectively
44 overriding and intercepting calls in that package to the built-in
45 "rand". It can also override "rand" in the current package or even
46 globally. In all of these cases, it also exports "srand" and "oneish"
47 to the current package in order to control the output of "rand". See
48 "USAGE" for details.
49
50 Alternatively, this module can be used to generate objects, with each
51 object maintaining its own distinct seed array.
52
54 By default, Test::MockRandom does not export any functions. This still
55 allows object-oriented use by calling "Test::MockRandom->new(@seeds)".
56 In order for Test::MockRandom to be more useful, arguments must be
57 provided during the call to "use".
58
59 use Test::MockRandom 'Target::Package'
60 The simplest way to intercept "rand" in another package is to provide
61 the name(s) of the package(s) for interception as arguments in the
62 "use" statement. This will export "rand" to the listed packages and
63 will export "srand" and "oneish" to the current package to control the
64 behavior of "rand". You must "use" Test::MockRandom before you "use"
65 the target package. This is a typical case for testing a module that
66 uses random numbers:
67
68 use Test::More 'no_plan';
69 use Test::MockRandom 'Some::Package';
70 BEGIN { use_ok( Some::Package ) }
71
72 # assume sub foo { return rand } was imported from Some::Package
73
74 srand(0.5)
75 is( foo(), 0.5, "is foo() 0.5?") # test gives "ok"
76
77 If multiple package names are specified, "rand" will be exported to all
78 of them.
79
80 If you wish to export "rand" to the current package, simply provide
81 "__PACKAGE__" as the parameter for "use", or "main" if importing to a
82 script without a specified package. This can be part of a list
83 provided to "use". All of the following idioms work:
84
85 use Test::MockRandom qw( main Some::Package ); # Assumes a script
86 use Test::MockRandom __PACKAGE__, 'Some::Package';
87
88 # The following doesn't interpolate __PACKAGE__ as above, but
89 # Test::MockRandom will still DWIM and handle it correctly
90
91 use Test::MockRandom qw( __PACKAGE__ Some::Package );
92
93 use Test::MockRandom %customized
94 As an alternative to a package name as an argument to "use",
95 Test::MockRandom will also accept a hash reference with a custom set of
96 instructions for how to export functions:
97
98 use Test::MockRandom {
99 rand => [ Some::Package, {Another::Package => 'random'} ],
100 srand => { Another::Package => 'seed' },
101 oneish => __PACKAGE__
102 };
103
104 The keys of the hash may be any of "rand", "srand", and "oneish". The
105 values of the hash give instructions for where to export the symbol
106 corresponding to the key. These are interpreted as follows, depending
107 on their type:
108
109 • String: a package to which Test::MockRandom will export the symbol
110
111 • Hash Reference: the key is the package to which Test::MockRandom
112 will export the symbol and the value is the name under which it
113 will be exported
114
115 • Array Reference: a list of strings or hash references which will be
116 handled as above
117
118 Test::MockRandom->export_rand_to()
119 In order to intercept the built-in "rand" in another package,
120 Test::MockRandom must export its own "rand" function to the target
121 package before the target package is compiled, thus overriding calls to
122 the built-in. The simple approach (described above) of providing the
123 target package name in the "use Test::MockRandom" statement
124 accomplishes this because "use" is equivalent to a "require" and
125 "import" within a "BEGIN" block. To explicitly intercept "rand" in
126 another package, you can also call "export_rand_to", but it must be
127 enclosed in a "BEGIN" block of its own. The explicit form also support
128 function aliasing just as with the custom approach with "use",
129 described above:
130
131 use Test::MockRandom;
132 BEGIN {Test::MockRandom->export_rand_to('AnotherPackage'=>'random')}
133 use AnotherPackage;
134
135 This "BEGIN" block must not include a "use" statement for the package
136 to be intercepted, or perl will compile the package to be intercepted
137 before the "export_rand_to" function has a chance to execute and
138 intercept calls to the built-in "rand". This is very important in
139 testing. The "export_rand_to" call must be in a separate "BEGIN" block
140 from a "use" or "use_ok" test, which should be enclosed in a "BEGIN"
141 block of its own:
142
143 use Test::More tests => 1;
144 use Test::MockRandom;
145 BEGIN { Test::MockRandom->export_rand_to( 'AnotherPackage' ); }
146 BEGIN { use_ok( 'AnotherPackage' ); }
147
148 Given these cautions, it's probably best to use either the simple or
149 custom approach with "use", which does the right thing in most
150 circumstances. Should additional explicit customization be necessary,
151 Test::MockRandom also provides "export_srand_to" and
152 "export_oneish_to".
153
154 Overriding "rand" globally: use Test::MockRandom 'CORE::GLOBAL'
155 This is just like intercepting "rand" in a package, except that you do
156 it globally by overriding the built-in function in "CORE::GLOBAL".
157
158 use Test::MockRandom 'CORE::GLOBAL';
159
160 # or
161
162 BEGIN { Test::MockRandom->export_rand_to('CORE::GLOBAL') }
163
164 You can always access the real, built-in "rand" by calling it
165 explicitly as "CORE::rand".
166
167 Intercepting "rand" in a package that also contains a "rand" function
168 This is tricky as the order in which the symbol table is manipulated
169 will lead to very different results. This can be done safely (maybe)
170 if the module uses the same rand syntax/prototype as the system call
171 but offers them up as method calls which resolve at run-time instead of
172 compile time. In this case, you will need to do an explicit intercept
173 (as above) but do it after importing the package. I.e.:
174
175 use Test::MockRandom 'SomeRandPackage';
176 use SomeRandPackage;
177 BEGIN { Test::MockRandom->export_rand_to('SomeRandPackage');
178
179 The first line is necessary to get "srand" and "oneish" exported to the
180 current package. The second line will define a "sub rand" in
181 "SomeRandPackage", overriding the results of the first line. The third
182 line then re-overrides the "rand". You may see warnings about "rand"
183 being redefined.
184
185 Depending on how your "rand" is written and used, there is a good
186 likelihood that this isn't going to do what you're expecting, no matter
187 what. If your package that defines "rand" relies internally upon the
188 system "CORE::GLOBAL::rand" function, then you may be best off
189 overriding that instead.
190
192 "new"
193 $obj = new( LIST OF SEEDS );
194
195 Returns a new Test::MockRandom object with the specified list of seeds.
196
197 "srand"
198 srand( LIST OF SEEDS );
199 $obj->srand( LIST OF SEEDS);
200
201 If called as a bare function call or package method, sets the seed list
202 for bare/package calls to "rand". If called as an object method, sets
203 the seed list for that object only.
204
205 "rand"
206 $rv = rand();
207 $rv = $obj->rand();
208 $rv = rand(3);
209
210 If called as a bare or package function, returns the next value from
211 the package seed list. If called as an object method, returns the next
212 value from the object seed list.
213
214 If "rand" is called with a numeric argument, it follows the same
215 behavior as the built-in function -- it multiplies the argument with
216 the next value from the seed array (resulting in a random fractional
217 value between 0 and the argument, just like the built-in). If the
218 argument is 0, undef, or non-numeric, it is treated as if the argument
219 is 1.
220
221 Using this with an argument in testing may be complicated, as limits in
222 floating point precision mean that direct numeric comparisons are not
223 reliable. E.g.
224
225 srand(1/3);
226 rand(3); # does this return 1.0 or .999999999 etc.
227
228 "oneish"
229 srand( oneish() );
230 if ( rand() == oneish() ) { print "It's almost one." };
231
232 A utility function to return a nearly-one value. Equal to ( 2^32 - 1 )
233 / 2^32. Useful in "srand" and test functions.
234
235 "export_rand_to"
236 Test::MockRandom->export_rand_to( 'Some::Class' );
237 Test::MockRandom->export_rand_to( 'Some::Class' => 'random' );
238
239 This function exports "rand" into the specified package namespace. It
240 must be called as a class function. If a second argument is provided,
241 it is taken as the symbol name used in the other package as the alias
242 to "rand":
243
244 use Test::MockRandom;
245 BEGIN { Test::MockRandom->export_rand_to( 'Some::Class' => 'random' ); }
246 use Some::Class;
247 srand (0.5);
248 print Some::Class::random(); # prints 0.5
249
250 It can also be used to explicitly intercept "rand" after
251 Test::MockRandom has been loaded. The effect of this function is
252 highly dependent on when it is called in the compile cycle and should
253 usually called from within a BEGIN block. See "USAGE" for details.
254
255 Most users will not need this function.
256
257 "export_srand_to"
258 Test::MockRandom->export_srand_to( 'Some::Class' );
259 Test::MockRandom->export_srand_to( 'Some::Class' => 'seed' );
260
261 This function exports "srand" into the specified package namespace. It
262 must be called as a class function. If a second argument is provided,
263 it is taken as the symbol name to use in the other package as the alias
264 for "srand". This function may be useful if another package wraps
265 "srand":
266
267 # In Some/Class.pm
268 package Some::Class;
269 sub seed { srand(shift) }
270 sub foo { rand }
271
272 # In a script
273 use Test::MockRandom 'Some::Class';
274 BEGIN { Test::MockRandom->export_srand_to( 'Some::Class' ); }
275 use Some::Class;
276 seed(0.5);
277 print foo(); # prints "0.5"
278
279 The effect of this function is highly dependent on when it is called in
280 the compile cycle and should usually be called from within a BEGIN
281 block. See "USAGE" for details.
282
283 Most users will not need this function.
284
285 "export_oneish_to"
286 Test::MockRandom->export_oneish_to( 'Some::Class' );
287 Test::MockRandom->export_oneish_to( 'Some::Class' => 'nearly_one' );
288
289 This function exports "oneish" into the specified package namespace.
290 It must be called as a class function. If a second argument is
291 provided, it is taken as the symbol name to use in the other package as
292 the alias for "oneish". Since "oneish" is usually only used in a test
293 script, this function is likely only necessary to alias "oneish" to
294 some other name in the current package:
295
296 use Test::MockRandom 'Some::Class';
297 BEGIN { Test::MockRandom->export_oneish_to( __PACKAGE__, "one" ); }
298 use Some::Class;
299 seed( one() );
300 print foo(); # prints a value very close to one
301
302 The effect of this function is highly dependent on when it is called in
303 the compile cycle and should usually be called from within a BEGIN
304 block. See "USAGE" for details.
305
306 Most users will not need this function.
307
309 • Test::MockObject
310
311 • Test::MockModule
312
314 Bugs / Feature Requests
315 Please report any bugs or feature requests through the issue tracker at
316 <https://github.com/dagolden/Test-MockRandom/issues>. You will be
317 notified automatically of any progress on your issue.
318
319 Source Code
320 This is open source software. The code repository is available for
321 public review and contribution under the terms of the license.
322
323 <https://github.com/dagolden/Test-MockRandom>
324
325 git clone https://github.com/dagolden/Test-MockRandom.git
326
328 David Golden <dagolden@cpan.org>
329
331 This software is Copyright (c) 2014 by David Golden.
332
333 This is free software, licensed under:
334
335 The Apache License, Version 2.0, January 2004
336
337
338
339perl v5.32.1 2021-01-27 Test::MockRandom(3)