This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author xtreak
Recipients asvetlov, brian.curtin, graingert, lisroach, xtreak, yselivanov
Date 2020-05-02.04:22:07
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1588393327.69.0.298278070027.issue40406@roundup.psfhosted.org>
In-reply-to
Content
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.
History
Date User Action Args
2020-05-02 04:22:07xtreaksetrecipients: + xtreak, brian.curtin, asvetlov, yselivanov, graingert, lisroach
2020-05-02 04:22:07xtreaksetmessageid: <1588393327.69.0.298278070027.issue40406@roundup.psfhosted.org>
2020-05-02 04:22:07xtreaklinkissue40406 messages
2020-05-02 04:22:07xtreakcreate