On Fri, Mar 18, 2016 at 11:26:13PM -0500, boB Stepp wrote: > If I had a function to roll a die, such as: > > import random > > def roll_die(num_sides): > return random.randint(1, num_sides) > > How would I write unit tests for this?
(1) One way would be to monkey-patch the random module with your own. Something like this: import mymodule # The module containing the roll_die function. class random: @staticmethod def myrandomint(a, b): return 5 save = mymodule.random try: mymodule.random = random assert mymodule.roll_die(100) == 5 finally: mymodule.random = save Better would be to set up myrandomint so that it returns a specific sequence of values, so you can write: assert mymodule.roll_die(100) == 5 assert mymodule.roll_die(100) == 23 assert mymodule.roll_die(100) == 17 assert mymodule.roll_die(100) == 2 (for example). One way to get a known sequence of values is like this: values = [5, 23, 17, 2] it = iter(values) func = functools.partial(next, it, 999) Now func is a function that takes no arguments and returns 5 the first time you call it, 23 the second time, and so on, and then returns 999 forever afterwards. (2) Another way is to use the random seed to get a predictable series of values: import mymodule mymodule.random.seed(95) assert mymodule.roll_die(6) == 3 assert mymodule.roll_die(6) == 2 assert mymodule.roll_die(6) == 6 assert mymodule.roll_die(6) == 6 assert mymodule.roll_die(6) == 5 But beware: Python only guarantees that changing the seed will give the same sequence of values for random.random(), *not* for the other random functions. So they can change according to the version of Python you are using. However, you know that given some specific version, the output of randint(a, b) will be the same when given the same seed. It may be different for another version. (3) A third approach is "dependency injection". Re-write your roll_die function like this: def roll_die(num_sides, randint=None): if randint is None: # Use the default randint from random import randint return randint(1, num_sides) Now, when testing, you can *explicitly* provide a "randint" function that returns whatever you like. Use the monkey-patch technique above, or your own custom random generator: import random myrand = random.Random() # Make an independent PRNG. myrand.seed(1000) # Seed to a known value # Record the values it gives. values = [myrand.randint(1, 6) for i in range(1000)] myrand.seed(1000) # Restore the seed. for expected_value in values: assert mymodule.roll_die(6, myrand.randint) == expected_value -- Steve _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor