Dictionaries shared among unit tests
I was recently writing some unit tests for some data serializer methods for a third party market data API in Django and one of my tests used a dictionary to mock a JSON response from an API. I wanted to be "DRY" so I reused the same dictionary and using a few class properties, I modified the values to represent different scenarios where the data might be invalid (this API is not very stable).
Ex:
from django.test import TestCase
class MarketIndexTestCase(TestCase):
self.market_response = {
"indexes": [
{
"id": "a023f176-328c-40eb-99a5-fe18c0b4eb32",
"name": "Dow Jones Industrial Average",
"is_data_only": True,
"symbol": "INDU"
"value": "19,237.25",
"last_trade_time": "2016-12-06T17:48:40.000000Z"
},
{
"id": "ae0fb991-5f6f-4e05-9a19-a50d040576ba",
"name": "Nasdaq Composite Index",
"symbol": "COMP"
"value": "5,250.17",
"last_trade_time": "2016-12-06T17:48:40.000000Z"
},
{
"id": "ae0fb991-5f6f-4e05-9a19-a50d040576ba",
"name": "S&P 500 Index",
"symbol": "INX"
"value": "2,208.81",
"last_trade_time": "2016-12-06T17:48:40.000000Z"
}
]
}
@property
def mock_invalid_change_in_value(self):
# Simulate an unexpected change in value
data = self.market_response
data['indexes'][0]['value'] = 'N/A'
return data
... (some tests) ...
The issue
The problem with the above code is that it is mutating the dictionary self.market_response
and any tests that require the original self.market_response
data will not be able to use it.
The solution
Since dictionaries in python are mutable, we should expect that any change to the dictionary (see mock_invalid_change_in_value
) will change the original dictionary. And because unit tests should be isolated, we should instead opt to use a copy of the dictionary in the mock_invalid_change_in_value
property
as such:
import copy
@property
def mock_invalid_change_in_value(self):
# Simulate an unexpected change in value
data = copy.deepcopy(self.market_response)
data['indexes'][0]['value'] = 'N/A'
return data
doing so would create a copy, leaving the original dictionary untouched.