Search code examples
pythonunit-testingrandom

How to validate a unit test with random values


How to validate a unit test with random values? I need guarantee that gen_age returns an integer between 15 and 99, but this code is not correct.

import random
import unittest


def gen_age():
    # generate integer between 15 and 99
    return random.randint(15, 99)


class AgeTest(unittest.TestCase):

    def setUp(self):
        self.a = gen_age()

    def test_choice(self):
        element = random.choice(self.a)
        self.assertTrue(element in self.a)

    def test_sample(self):
        for element in random.sample(self.a, 98):
            self.assertTrue(element in self.a)

if __name__ == '__main__':
    unittest.main()

Solution

  • The best way to test a similar behaviors is to set a seed to the Random object.

    The random package provide a Random class. Instances of Random have the same methods than the random package; random(), randint(), sample(), ... In addition, Random accepts a seed. Adding a seed to Random makes it outputs deterministic. For example,

    from random import Random
    random = Random(666)
    assert random.randint(0, 1000) == 467  # will never break
    

    Consequently, you would like to tests your function as

    from random import Random
    import unittest
    
    random = Random()
    
    def gen_age():
        # generate integer between 15 and 99
        return random.randint(15, 99)
    
    
    class AgeTest(unittest.TestCase):
    
        def setUp(self):
            global random
            random = Random(666)
    
        def test_gen_age(self):
            self.assertEqual(gen_age(), 53)
    
    if __name__ == '__main__':
        unittest.main()
    

    Note that if your test is not in the same file, you will need to patch random using unittest.mock.patch. Something like that should work

    from random import Random
    from package.file import gen_age
    import unittest
    from unittest.mock import patch
    
    
    class AgeTest(unittest.TestCase):
    
        def setUp(self):
            self.random = Random(666)
    
        @patch('package.file.random')
        def test_gen_age(self, random):
            random.randint._mock_side_effect = self.random.randint
            self.assertEqual(gen_age(), 53)