I have a Python TestCase
class where all test methods, except one, need to patch an object the same way. The other method need some other behavior from the same object. I'm using mock, so I did:
@mock.patch('method_to_patch', mock.Mock(return_value=1)) class Tests(TestCase): @mock.patch('method_to_patch', mock.Mock(return_value=2)) def test_override(self): (....)
But that's not working. When test_override
is run, it still calls the patched behavior from the class decorator.
After a lot of debugging, I found out that during the TestSuite
build, the @patch
around test_override
is being called before the one around Tests
, and since mock
apply the patches in order, the class decorator is overriding the method decorator.
Is this order correct? I was expecting the opposite and I'm not really sure how to override patching... Maybe with a with
statement?
To patch a decorator, you need to either import or reload the module which uses that decorator after patching it OR redefine the module's reference to that decorator altogether. Decorators are applied at the time that a module is imported.
So what is the difference between them? MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use (e.g. __str__ , __len__ , etc.). Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.
MagicMock. MagicMock objects provide a simple mocking interface that allows you to set the return value or other behavior of the function or object creation call that you patched. This allows you to fully define the behavior of the call and avoid creating real objects, which can be onerous.
Well, turns out that a good night sleep and a cold shower made me rethink the whole issue. I'm still very new to the concept of mocking, so it still hasn't sunk in quite right.
The thing is, there's no need to override the patch to a mocked object. It's a mocked object and that means I can make it do anything. So my first try was:
@mock.patch('method_to_patch', mock.Mock(return_value=1)) class Tests(TestCase): def test_override(self): method_to_patch.return_value = 2 (....)
That worked, but had the side effect of changing the return value for all following tests. So then I tried:
@mock.patch('method_to_patch', mock.Mock(return_value=1)) class Tests(TestCase): def test_override(self): method_to_patch.return_value = 2 (....) method_to_patch.return_value = 1
And it worked like a charm. But seemed like too much code. So then I went the down the road of context management, like this:
@mock.patch('method_to_patch', mock.Mock(return_value=1)) class Tests(TestCase): def test_override(self): with mock.patch('method_to_patch', mock.Mock(return_value=2): (....)
I think it seems clearer and more concise.
About the order in which the patch
decorators were being applied, it's actually the correct order. Just like stacked decorators are applied from the bottom up, a method decorator is supposed to be called before the class decorator. I guess it makes sense, I was just expecting the opposite behavior.
Anyway, I hope this help some poor newbie soul like mine in the future.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With