# It is good practice to reuse unit test for different functions in Python

I'm new to unit testing and want to start with a nose frame . But answers using unittest , pytest are welcome too. Also, of course, general advice.

I think I am getting the basic concept, but I am lacking practice in setting up a good test. I am also struggling with how to deploy tests. I'm especially unsure about how to approach the case where I want to run multiple test cases on a different module function:

For example: I might have a module called `diceroller.py`

it contains a couple of functions to simulate rolling, change and check results, etc. All dice rolling functions must run through the same tests (whether they return integers with the right number of values, values ββin a range, etc.). But some of them should also be directed against some additional cases.

So I got a subdir `test`

and want to install my test code there. How do I approach this?

```
# a section of `diceroller.py`
def roll_a_dice(sides=6):
"""Return an integer x where `x >= 1 <= sides`"""
return random.randint(1, sides)
def roll_dice(sides=6, count=1):
"""Return a list of integers (most function except this)"""
rolls = list()
while count:
rolls.append(random.randint(1, sides))
count -= 1
return rolls
def roll_some_dice(sides=6, count=1, times=1):
"""Return a list of list containing integers"""
some_rolls = list()
while times:
some_rolls.append(roll_dice(sides, count))
times -= 1
return some_rolls
def rolling_dice(sides=6, count=1):
"""Yielding integers `count` times"""
while count:
count -= 1
yield random.randint(1, sides)
```

** Small update**

Simeon Visser has a good point. But the above code, where it just functions, also contains some context for my Questions, namely: how can I (re) use test cases for different functions?

I am guessing that writing tests like `check_xyz`

and then calling it from `test_a`

and `test_b`

for example is the simplest solution? Or is it bad practice?

Rik Poggi's solution seems to do what it was trying to do (will play with it immediately after entering this text). But I have a feeling it "complicates" things for a lot of people ... maybe not technically, but it might seem "too big".

source to share

I will not consider the problem that the test code is clearly having to check. I will focus on your question about test code reuse.

** Important things to keep in mind before starting:**

- Tests should be simple (no or very little logic inside).
- Tests must be readable (they are like code documentation).
- Tests must be maintainable.

The simplicity of your tests is a must, and in doing so, you need to find the right balance between the last two points.

**One final warning:** Be very careful when reusing test code, because if you do it wrong, your tests will listen. Test errors are hard to spot, but after a year you may find one, a seed of doubt will be planted and the credibility of your tests may diminish. Tests that you do not trust ("oh, that fails, but unreasonable because the other fails too, etc.") Completely and completely useless.

Now that we've cleared our path, let's take a look at your code. Usually the dynamic part of the tests is achieved through the context (methods `setUp`

and `tearDown`

), but in your case it's a little more complicated.

I want to run multiple test cases on different module functions.

You don't really want the same test case to run with a different function, but only with the same code. A good test environment will have (at least) one test case for each feature.

Since you are looking for the ability to run a previous test case / package against the partial output of another function, you will need `functools.partial`

one that will allow you to wrap your function with default arguments.

This means that you should start at the bottom, starting with the simplest tests:

```
def check_valid_range(value, sides):
"""Check that value is a valid dice rolling"""
assert 0 < value <= sides
def check_is_int(value):
"""Check that value is an integer"""
assert type(value) is int
```

And then build on top of them (with little connectivity):

```
class TestRollADice:
"""roll_a_dice basic tests"""
@staticmethod
def func_to_test(*args, **kwargs):
return diceroller.roll_a_dice(*args, **kwargs)
@staticmethod
def check_valid_output(value, sides):
"""Check that value is the self.function is valid"""
yield check_valid_range, value, sides
yield check_is_int, value
def test_3sides(self):
"""Check valid result for a 3 sides dice"""
yield self.check_valid_output, self.func_to_test(3), 3
def test_list_valid_sides(self):
"""Check valid result for a list of valid sides (sides >= 3)"""
sides = list(range(3, 13))
for s in sides:
yield self.check_valid_output, self.func_to_test(s), s
def test_0_sides_raises_ValueError(self):
"""0 side dice raise ValueError"""
assert_raises(ValueError, self.func_to_test, 0)
def test_1_sides_raises_ValueError(self):
"""1 side dice raise ValueError"""
assert_raises(ValueError, self.func_to_test, 1)
def test_2_sides_raises_ValueError(self):
"""2 sides dice raise ValueError"""
assert_raises(ValueError, self.func_to_test, 2)
def test_minus1_sides_raises_ValueError(self):
"""-1 side dice raise ValueError"""
assert_raises(ValueError, self.func_to_test, -1)
```

This is the minimum number of tests your function should have `roll_a_dice`

. Try running `nosetests`

in your package and you will see two of them don't work, see how important the tests are! :)

I'm sure you noticed how the test name is verbose for readability.

Now for the `roll_dice`

main test class has to test these three, four main values ββand baisc errors, because the good thing should be simple and keep under control what is being tested, I would say that you might need some functionality like:

```
def check_list_length(self, lst, count):
"""Check that the len(lst) == count"""
assert len(lst) == count
def check_valid_count(self, count):
"""Check count > 0"""
assert count > 0
class TestRollDice:
# ...
```

And now, if you want to reuse old code, you can subclass `TestRollADice`

:

```
from functools import partial
class TestRollDice_Count1(TestRollADice):
@staticmethod
def func_to_test(*args, **kwargs):
return partial(diceroller.roll_dice, count=1)(*args, **kwargs)
```

And voilΓ , almost free, you will have twice as many tests :)

** Note:**

- All of the above codes can be written in the language
`unittest`

, but since you asked about`nose`

, I wrote with that. - There is a small problem: the docstras for passing tests are the same, so they appear twice in verbose output. This is not a big problem, as if one of these tests fails, you will be prompted for a test address and that it is unique (and clearly, because luckily our test names are verbose). I also remember that docstrings can be disabled or something. So again, this is not a big problem and it should be easy for you to find a workaround if needed.

source to share

Your code can be refactored to reduce the amount of code, and therefore the amount of code that needs to be tested. Let's see what you want:

- Roll the dice (
`roll_a_dice`

) - Roll the dice several times (
`roll_dice`

) - Get some rolls where the cubes have been rolled multiple times (
`roll_some_dice`

)

Let's rewrite it first `roll_dice`

. We basically want to call `roll_a_dice`

multiple times and put the results in a list:

```
def roll_dice(sides=6, count=1):
"""Return a list of integers (most function except this)"""
return [roll_a_dice(sides) for i in xrange(count)]
```

Do the same with `roll_some_dice`

: we want to call `roll_dice`

multiple times and put the results in a list:

```
def roll_some_dice(sides=6, count=1, times=1):
"""Return a list of list containing integers"""
return [roll_dice(sides, count) for i in xrange(times)]
```

Finally, `rolling_dice`

it still contains some logic:

```
def rolling_dice(sides=6, count=1):
"""Yielding integers `count` times"""
while count:
count -= 1
yield roll_a_dice(sides)
```

The code is now much easier to check for errors and easier to unit test:

```
import random
def roll_a_dice(sides=6):
"""Return an integer x where `x >= 1 <= sides`"""
return random.randint(1, sides)
def roll_dice(sides=6, count=1):
"""Return a list of integers (most function except this)"""
return [roll_a_dice(sides) for i in xrange(count)]
def roll_some_dice(sides=6, count=1, times=1):
"""Return a list of list containing integers"""
return [roll_dice(sides, count) for i in xrange(times)]
def rolling_dice(sides=6, count=1):
"""Yielding integers `count` times"""
while count:
count -= 1
yield roll_a_dice(sides)
```

Now you can write a test case to check if the dice rolls correctly ( `roll_a_dice`

). Once you've tested this, you no longer need to do this for other functions. For these functions, you only need to check if the correct number of results was received (because any wrong values ββshould have been caught by the test case (s) for `roll_a_dice`

).

Likewise, when you test `roll_some_dice`

, you can assume what is `roll_dice`

working correctly because you have already written tests for that function. If something goes wrong, you can add the test to the test case for `roll_dice`

, not `roll_some_dice`

(unless the problem is defined for `roll_some_dice`

).

source to share