I’m unit testing my application. What most of the tests do is calling a function with specific arguments and asserting the equality of the return value with an expected value.
In some tests the expected return value is a relatively big object. One of them, for example, is a dictionary which maps 5 strings to lists of tuples. It takes 40-50 repetitive lines of code to define that object, but that object is an expected value of one of the functions I’m testing. I don’t want to have a 40-50 lines of code defining an expected return value inside a test function because most of my test functions consist of 3-6 lines of code. I’m looking for a best practice for such situations. What is the right way of putting lengthy definitions inside a test?
Here are the ideas I was thinking of to address the issue, ranked from the best to the worst as I see it:
-
Testing samples of the object: Making a few equality assertions based on a subset of the keys. This will sacrifice the thoroughness of the test for the sake of code elegance.
-
Defining the object in a separate module: Writing the lengthy 40-50 lines of code in a separate .py file, importing the module in the test and then make the equality assertion. This will make the test short and concise but I don’t like having a separate file as a supplement to a test; the object definition is part of the test after all.
-
Defining the object inside the test function: This is the trivial solution which I wish to avoid. My tests are pretty simple and straightforward and the lengthy definition of that object doesn’t fit.
Maybe I’m too obsessed with clean code, but I like none of the above solutions. Is there another common practice I haven’t thought of?
I’d suggest using a separation of testing code and testing data. For this reason I usually create an abstract base class which contains the methods I’d like to test and create several specific test case classes to tie the methods to the data. (I use the Django framework, so all abstract test classes I put into
testbase.py):testbase.py:
and now the implementations in test.py
The test data can also be externalized, e.g a JSON file:
I hope I made my points clear enough. In your case I’d strongly opt for using data files. Django supports this out-of-the-box by using test fixtures to be loaded into the database prior executing any tests.