pytest-mock
pytest-mock copied to clipboard
Allow use of custom mock implementations
With the growing use of asyncio, we need ways to mock Coroutines.
Currently, mock and unittest.mock do not support creating specs for coroutines (AsyncMock is being added in python 3.8).
As a work around, we're using asynctest.mock, which has the same interface as unittest.mock, however this requires us to completely re-implement the __init__ method of MockFixture, and removes the "hide traceback" functionality (though we don't care too much about this).
This allows us to have both mocker and async_mocker fixtures.
TLDR To ease this usecase (and potentially others), Can support for defining a mock modules path from the config be added please?
Please note: asynctest.mock.CoroutineMock is not compatible with unittest.mock.AsyncMock.
It is not a drop-in replacement.
Moreover, AsyncMock doesn't exist on it's own, it is deeply integrated with other unittest.mock objects and functions. Thus, the whole unittest.mock should be replaced with asynctest.mock with even more incompatibility level.
I rather suggest not touching pytest-mock library but wait for 3.8.
Similar but slightly different API makes more harm than help.
The support of such solutions is hard in long term perspective.
If you really need asynctest.mock.CoroutineMock support you can clone pytest-mock, add needed hacks, and use it on your own.
I didn't take a look at the problem in detail, but @asvetlov makes a point about supporting slightly different APIs in the same package brings more problems than it helps.
Perhaps we should create a new pytest-asyncmock plugin instead?
agree with your points on this. I think it's probably best to wait until 3.8 for this library.
In terms of creating a new plugin, it might be better to try and get the fixtures into the asynctest library instead.
Will close this issue for now.
The hack we have in place works well enough for us until that time, and for our specific usecase, it will be an easy migration.
If anyone else stumbles on this issue, here is the hack:
import pytest
import pytest_mock
import asynctest.mock
@pytest.fixture
def async_mocker(pytestconfig):
# This is a straight copy + paste from pytest_mock, but with our patched MockFixture
result = AsyncMockFixture(pytestconfig)
yield result
result.stopall()
class AsyncMockFixture(pytest_mock.MockFixture):
def __init__(self, config):
# This is a straight copy + paste from pytest_mock
# TODO: contribute a way to use arbitary mock libraries upstream
self._patches = [] # list of mock._patch objects
self._mocks = [] # list of MagicMock objects
# CHANGED: hard coding the asynctest.mock
self.mock_module = mock_module = asynctest.mock
self.patch = self._Patcher(self._patches, self._mocks, mock_module)
# aliases for convenience
self.Mock = mock_module.Mock
self.MagicMock = mock_module.MagicMock
self.NonCallableMock = mock_module.NonCallableMock
self.PropertyMock = mock_module.PropertyMock
self.call = mock_module.call
self.ANY = mock_module.ANY
self.DEFAULT = mock_module.DEFAULT
self.create_autospec = mock_module.create_autospec
self.sentinel = mock_module.sentinel
self.mock_open = mock_module.mock_open
# CoroutineMock is from asynctest
# AsyncMock is being added in python 3.8
# Please use AsyncMock.
self.CoroutineMock = self.AsyncMock = mock_module.CoroutineMock
Python 3.8 is out. It might be worth reopening this issue as there's AsyncMock available now.
Thanks for the ping @jack1142.
Will gladly accept PRs in this regard if all it is required is to provide a custom mock implementation, but I probably would not like to include it into pytest-mock it this would require an entire new implementation of pytest_mock.MockFixture.
~~mock since version 4.0.0 has the AsyncMock class which could be exposed directly through mocker.AsyncMock (like the usual mocker.Mock)~~
EDIT: Sorry I thought pytest-mock had a dependency on mock, but this is not the case so it's not as easy as I thought.
FWIW, AsyncMock is now available as part of mocker from https://github.com/pytest-dev/pytest-mock/commit/449d3d038e076fcdbb860815d306d4a59db44141 with rich assert diff for assert helpers associated with AsyncMock