--- tags: [Python Unit Tests at Hypothesis] redirect_from: - /post/patch/ --- Hypothesis's patch Fixture ========================== In [The Problem with Mocks]({{ site.baseurl }}{% post_url 2017-03-17-the-problem-with-mocks %}) we discussed some of the potential problems with mock-based tests. In this post we'll discuss one of the most useful, and least problematic, ways that mock is used in the Hypothesis tests - `patch()`. patch ----- One of the best uses for mocks in the Hypothesis tests is through [the `patch` fixture](https://github.com/hypothesis/h/blob/f4439313dab7d50f83f55e9c3f8693307e0df5d9/tests/h/conftest.py#L207). `patch` is a custom [pytest fixture](/posts/fixtures) that integrates [`mock.patch`](http://www.voidspace.org.uk/python/mock/patch.html?highlight=patch#mock.patch) (a feature of the mock library that we haven't discussed) with pytest fixtures. You'll see `patch` used very often in the Hypothesis tests. `patch` is most often used when one of our modules `import`s and uses another one of our own modules. `patch` replaces the other module with a `MagicMock` object. For example, [h/views/api.py::create()](https://github.com/hypothesis/h/blob/ca1681203aff5ee176fd880cb01fb04f1c7e1a5a/h/views/api.py#L207) is the view function that's called when someone `POST`s a new annotation to the `https://hypothes.is/api/annotations` URL. It calls the `storage` module to save the new annotation to the database. `storage` has its own tests and we don't want our test for `create()` to be accessing the real database, so we want `storage` to be replaced with a mock object. This is done using a simple `patch`-based fixture: ```python class TestCreate(object): def test_it_creates_the_annotation_in_storage(self, storage): ... # (Call the create() view to create an annotation) # Use the mock storage object to test that it would have saved the # annotation to storage. storage.create_annotation.assert_called_once_with(...) @pytest.fixture def storage(self, patch): # Replace h.views.api.storage with a mock object, and return the # mock object. return patch('h.views.api.storage') ``` The code under test, `h/views/api.py`, imports another module `h/storage.py` like this: ``` from h import storage ``` In the tests above, the `storage()` fixture calls `patch('h.views.api.storage')` which replaces the `storage` module in `h/views/api.py` with a mock object. Since `test_something_about_search()` uses the `storage()` fixture, any `views.py` code that this test calls will see a mock object in place of the real `storage` module. The `storage()` fixture happens to have the same name as the `storage` module it replaces - this isn't necessary, the `storage()` fixture could be called anything and still replace the `storage` module - but giving patch fixtures the same name as the thing they patch is a convention in the Hypothesis tests. `patch` is an unusual fixture in that it's almost always used by other fixtures, like the `storage` fixture above, rather than by tests directly. `patch` automatically takes care to do the mocking in the best way possible: * It uses [autospec]({{ site.baseurl }}{% post_url 2017-03-17-the-problem-with-mocks %}) so that, just like when creating a `MagicMock` with `create_autospec()`, only those attributes that exist on the real object can be accessed or set on the mock (recursively). **Call signatures** are also matched: if code passes the wrong number of arguments, or a keyword argument that doesn't exist on the real method, to a mock object from the `patch` fixture it'll get a `TypeError` just as you would get from the real object. * `patch` also takes care of stopping the patch after the test method finishes, before the next test is run, so that one test's mock object doesn't leak into other tests. It still isn't perfect (see [The Problem with Mocks]({{ site.baseurl }}{% post_url 2017-03-17-the-problem-with-mocks %}) for the limitations of autospeccing) but `patch` is one of the most useful and least problematic applications of the mock library and you'll see it used a lot in the Hypothesis tests. In the next post we'll look at a pytest feature that's often used in combination with patch - [the usefixtures decorator]({{ site.baseurl }}{% post_url 2017-03-17-usefixtures-class-decorator %}).