简体   繁体   中英

Overriding Python mock's patch decorator

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM