Skip to content

Allow use of custom mock implementations #150

Open

Description

@antdking

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?

Activity

  1. asvetlov commented on Jun 27, 2019

    @asvetlov

    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.

  2. nicoddemus commented on Jun 27, 2019

    @nicoddemus
    Member

    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?

  3. antdking commented on Jun 28, 2019

    @antdking
    Author

    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
  4. Jackenmen commented on Oct 24, 2019

    @Jackenmen

    Python 3.8 is out. It might be worth reopening this issue as there's AsyncMock available now.

  5. nicoddemus commented on Oct 24, 2019

    @nicoddemus
    Member

    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.

  6. ThibaultLemaire commented on May 15, 2020

    @ThibaultLemaire

    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.

  7. tirkarthi commented on Jul 26, 2020

    @tirkarthi
    Contributor

    FWIW, AsyncMock is now available as part of mocker from 449d3d0 with rich assert diff for assert helpers associated with AsyncMock

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions