Reputation: 91
For each of my tests in a unittest.TestCase
suite, I need to do some setup: run a function that returns a different value for each test (depending on some properties of each test that are passed as arguments to the setup function).
There is the setUp()
hook that I could use, but it does not return a value and does not accept arguments. But let's say arguments aren't important in this case.
What strategy is recommended?
setUp()
with global variablessetUp()
with class or instance variablesUpvotes: 0
Views: 4813
Reputation: 5939
Note my destinction between setup and Setup
below: Each test has to so some setup activities, but these are not necessarily put into the Setup
method.
My preference is that each test function should be easily understood by itself. I don't want to look at test code wondering "where does this value suddenly come from" or the like. Which means, I avoid a common Setup
method but instead use helper functions / methods that also have descriptive names. To be more precise:
makeTrafficLightInGreenState
for a helper factory to produce a specific type of traffic light object. In this example I could then also have makeTrafficLightInRedState
for a different group of tests. I find this preferrable over a common Setup
method which just creates both the green and the red traffic light: In the end you get confused which part of Setup
is relevant for which test. Certainly, when writing your helper methods, you are also free to give them parameters, which could in the traffic light example result in 'makeTrafficLightInState(green)'. But, which approach to choose here is situation specific.Setup
.Setup
, but only for activities that are not necessary for understanding the logic of the test cases. For example, if there is some original state that needs to be preserved at the beginning of the test cases and to be restored afterwards, this could be put into Setup
without any negative impact on the readability of the individual test cases.In your case, you seem to already have a function with parameters that is suited to deliver test case specific data. I would simply call that function from each test case that needs it. Or, if calling that function is not simple (you have to create additional objects as arguments for it or the like), again put it into a helper method.
Upvotes: 0
Reputation: 5359
I follow the general strategy of, if a variable will be used in multiple test functions, I define it in the setUp()
. If it will only be used once local to a specific function, define it in that function.
Take the following example:
Say I have a python module in package program
called list_utils.py
and in list_utils.py
I have the following functions:
def list_to_string(mylist):
""" Takes a list of strings and joins them into a single string.
"""
return ' '.join(mylist)
def list_extender(mylist, extend_item):
return mylist.extend(extend_item)
Then I setup my unittest script with specifying mytestlist
because it will be used in multiple test functions:
from program import list_utils as lu
class TestListUtils(unittest.TestCase):
"""
A subclass of unittest to test list_utils.py
"""
def setUp(self):
self.mytestlist = ['Hi', 'there']
def test_list_to_string(self):
"""
Ensures my list is converted to string
"""
self.assertTrue(isinstance(lu.list_to_string(self.mytestlist), string))
def test_list_extender(self):
"""
Ensures list is extended when argument is passed.
"""
mylocalvariable = 'Adam'
self.assertTrue(lu.list_extender(self.mytestlist, mylocalvariable)[-1] == 'Adam')
def tearDown(self):
pass
if __name__ == '__main__':
unittest.main()
You see that for list_extender
I passed in mylocalvariable
because I would only use it in the scope of that function, but mytestlist
was defined in setUp
because I used it multiple times. By following this general approach, you shouldn't bloat your setUp
too much, and you also won't have to re-instantiate variables at each specific unittest if they will be used multiple times.
Upvotes: 2