so I’m writing unit tests and I’m having trouble with the setUp function. From what I’ve seen, it’s supposed to just execute code before your function and thus I could put anything that’s repetitive in there. However, this function doesn’t seem to be applying the mocks I’ve created as patch decorators over the entire class. This is a small piece of what I want it to look like:
@patch('geomet_data_registry.layer.base.get_today_and_now', new=mocked_get_date) # noqa
@patch('geomet_data_registry.layer.base.load_plugin', new=mocked_load_plugin)
@patch('geomet_data_registry.layer.base.TILEINDEX_PROVIDER_DEF', new=mocked_tileindex) # noqa
@patch('geomet_data_registry.layer.base.STORE_PROVIDER_DEF', new=mocked_store)
class TestInitBase(unittest.TestCase):
def setUp(self):
""" Code that executes before every function. """
self.maxDiff = None
self.today_date =
datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z')
mocked_get_date.return_value = self.today_date
self.base_layer = BaseLayer({'name': 'model_gem_global'})
def test_Init(self):
expected_values = {'items': [],...
base_layer_attr = self.base_layer.__dict__
self.assertDictEqual(expected_values, base_layer_attr, msg=None)
Here I mock the date received so it doesn’t mess with my tests, I mock load_plugin, which when used returns a class instance of a certain plugin, I mock TileIndex which is an ES TileIndex and I mock the store, which is a redis store. If I use the code shown above, it doesn’t work. When I instantiate the class BaseLayer
inside setUp
, none of my mocks are used and I get:
- 'receive_datetime': '2021-11-10T12:56:07.371067Z',
? ^^^
+ 'receive_datetime': '2021-11-10T12:56:07.371131Z',
? ^^^
- 'store': <MagicMock name='mock()' id='140158154534472'>,
- 'tileindex': <MagicMock name='mock()' id='140158154534472'>,
+ 'store': <BaseStore> Redis,
+ 'tileindex': <ElasticsearchTileIndex> http://localhost:9200,
However, before you tell me maybe my paths are wrong for the mocks or something like that, I can assure you that everything works fine, because the code works if I keep everything the same, except I repeat the class instantiation in every test function. Moreover, it will work if I keep this the same, but I name the setUp
for example mySetUp
and call it at the beginning of the function.
Everything works this way and I’ve already made all my tests without using the setUp
at all because I remember thinking to myself "this thing is broken I’m not risking using this function in my tests".
Thanks!
2
Answers
The problem is that the
mock.patch
decorator is applied to each test function, and duringsetUp
the patching has not been done yet.To use the same mocks for all tests, you have to start/stop mocking in
setUp
/tearDown
instead. This could look something like:Admittedly this is not as nice as using the decorators. You can still use the decorators for the functions that don’t have to already be patched in
setUp
, if there are any.As a side note: with
pytest
this would be a bit less messy, as you can have the setup and teardown part in the same fixture.By default the mock.patch decorator is applied to each function in the class starting with
test
. SincesetUp
does not start withtest
it will not be patched by the class decorator by default.You can change this by setting
patch.TEST_PREFIX
(https://docs.python.org/3/library/unittest.mock.html#test-prefix). If you want it to apply tosetUp
as well you can doand use the class decorators as before.