What is the best practice when writing Perl tests related to randomness?

While working on some updates to my List :: Gen module, I decided to add a method ->pick(num) , which will return the num size of random elements from its source. To test this, I used srand to seed a random number generator and conducted several form tests:

 srand 1234; is $src->pick(5)->str, '3 6 1 7 9'; 

And all this worked well on the Windows machine I was in at that time. However, when I moved the project to a Mac workstation, all randomness tests failed because, despite the fact that they have the same random seed, rand produced different results. I understand that these are from different base implementations of C rand() .

So the question is, what is the best cross-platform way to test these features? Should I overload the rand function with my own? Should I create bindings to functions using rand in order to enable the "test" mode, which produces predictive output? Are there other methods?

I would prefer answers that include basic Perl methods, as I try to keep the module dependency tree small.

Test :: Random and Test :: MockRandom seem to be CPAN suggestions, does anyone have any experience with these modules?

+6
source share
4 answers

I have not used any.

It seems like Test :: Random would be the best choice for you, since you are apparently just using randomness in your testing and not in your released code. It should be a lot easier to use.

The Test :: MockRandom module forces the rand () function to return a deterministic sequence.

+2
source

You can run several options and make sure that they do not all return the same. What the purpose of the function, after all.

0
source

I prefer to simply encapsulate environmental dependency and redefine it for testing purposes, a test pattern called Test Stub . Test Stub also covers other indirect inputs, such as system time and files. All of them should be interpreted as different forms of the same problem, so I believe that CPAN solutions for this problem are less than great.

As applied to the random number field, we have something like:

 use strict; use warnings; package Foo; sub new { my ($class) = @_; return bless {} => $class; } sub get_random_number { return rand(); } package main; use Test::MockObject::Extends; use Test::More tests => 1; my $foo = Test::MockObject::Extends->new( Foo->new() ); $foo->set_series(get_random_number => 0.5, 0.001, 0.999); is( $foo->get_random_number, 0.5 ); 

This leads to the fact that the system remains unchanged, with the exception of refactoring, which it should have in any case, but provides control points for entering predicted data into the test. get_random_number will not be covered by tests, so it is very important that it be written in such a way as to be accurate when checking; one call to a system resource depends on everything that should be there.

In the case of your specific problem, you need to determine the dependency on rand out from pick , and then override the extracted method in the checked version of List::Gen Test::MockObject::Extends is pretty much perfect for this need.

0
source

Maybe the random part doesn't matter for your tests?

Passing tests can verify the following:

  • did → pick (X) return X elements?
  • Are all X elements part of the $ src list?
  • Test for 0, 1, etc.
  • (maybe?) Check that two different srand semesters return different lists.

This is essentially what you are already doing, as you are trying to deduce rand () from the equation. It can also go all the way and check that your function does what it says on tin.

0
source

Source: https://habr.com/ru/post/886261/


All Articles