Testing with mock in Python 2015-02-23
Mocking is pretty awesome in python, especially when using the Mock library. It simplifies making stubs when testing, covers partial mocking, setting custom return values, how they were called, etc.
However there are a few pitfalls when initially working with Mock. Some of these things are pretty obvious, but this is a quick reference for a few gotchas I found while mocking a few projects.
side_effect vs return_value:
You'd only use
side_effect if you want to test something that happens in a function instead of a return value. For example if you want to test exceptions that are raised in a method, use
dork_mock = mock.Mock() dork_mock.some_method.side_effect = ZeroDivisionError dork_mock.some_method() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "build/bdist.linux-x86_64/egg/mock.py", line 955, in __call__ File "build/bdist.linux-x86_64/egg/mock.py", line 1010, in _mock_call ZeroDivisionError
When to use Mock vs. MagicMock
Basically with MagicMock you can mock magic methods. That's pretty much the only difference, otherwise you should use
Mock. as the docs say, one tiny thing to remember is that MagickMock returns set default values for some preconfigured methods:
m = MagicMock() int(m) # 1
Used as a context manager, it makes a specific context when your mocked modules live. You'll need to use mock.patch() when you want to mock modules in the classes you test. e.g.:
with mock.patch('module.to.test.first_module') as first_mock: with mock.patch('module.to.test.second_module') as second_mock:
If you are doing more than one, you can write is like this so your identations don't go crazy:
with mock.patch('module.to.test.first_module') as first_mock,\ mock.patch('module.to.test.second_module') as second_mock:
If you are mocking methods on modules, you can put them in the return value to save you some lines + style:
with mock.patch('module.to.test.first_method', return_value='flickity flam'):
I've seen mainly the above in our test cases, but you can use
patch as a decorator too, and mock the class as you go:
from mock import patch @patch('class_to_mock.the_method') def test_the_method(self, the_method) the_method.return_value = 'awesome'