[issue40406] MagicMock __aenter__ should be AsyncMock(return_value=MagicMock())

Karthikeyan Singaravelan report at bugs.python.org
Sat May 2 00:22:07 EDT 2020


Karthikeyan Singaravelan <tir.karthi at gmail.com> added the comment:

MagicMock object on call returns another MagicMock. AsyncMock object in turn returns a coroutine which has to be awaited. 

In the report mock.MagicMock().__aenter__() returns an AsyncMock object. Accessing the query attribute will create an AsyncMock object. Calling query() will return a coroutine which will not have a __aexit__. Mock supports configure_mock through which nested calls can be mocked but the return_value has to be accessed to mock the nested attributes. So a workaround could be below. The connection object is mocked such that the __aenter__ returns a MagicMock. That magic mock can have the query attribute to be mocked whose return_value is an AsyncMock if the the query object has to awaited.

See also issue37052 regarding adding an example. See also https://github.com/python/cpython/pull/16859 regarding adding an example along similar database mocking that will help.

>>> from unittest.mock import MagicMock, AsyncMock
<MagicMock name='mock()' id='140285187747744'>
>>> AsyncMock()()
<coroutine object AsyncMockMixin._mock_call at 0x7f96b0c5f3c0>


import asyncio
from unittest.mock import MagicMock, AsyncMock, patch


class Database:
    pass


async def mock_database():
    with patch(f"{__name__}.Database") as db:
        db.configure_mock(
            **{
                "connection.return_value.__aenter__.return_value": MagicMock(
                    **{
                        "query.return_value.__aenter__.return_value": AsyncMock(
                            return_value=[1]
                        )
                    }
                )
            }
        )

        async with db.connection() as conn:
            async with conn.query() as query:
                result = await query("select * from people")
                assert result == [1]
                print(f"Result : {result}")


asyncio.run(mock_database())


Hope it helps.

----------

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue40406>
_______________________________________


More information about the Python-bugs-list mailing list