Martiusweb / asynctest

Enhance the standard unittest package with features for testing asyncio libraries
https://asynctest.readthedocs.org/
Apache License 2.0
309 stars 41 forks source link

MagicMock looks to not be setting parents correctly #155

Closed jack-burridge-tp closed 4 years ago

jack-burridge-tp commented 4 years ago

I have some code in which I care about the order of the calls to different objects

Below is a minimal example task.py.

import asyncio

async def do_thing(arg):
    print(arg)

async def do_task():
    await do_thing('one')
    await asyncio.sleep(2)
    await do_thing('two')

The test is test_task.py

import asyncio

import pytest
from asynctest import patch, MagicMock, call

import task

@pytest.mark.asyncio
async def test_order():
    parent_mock = MagicMock()
    with patch.object(asyncio, 'sleep') as mock_sleep, patch.object(
        task, 'do_thing'
    ) as mock_do_thing:
        parent_mock.sleep = mock_sleep
        parent_mock.do_thing = mock_do_thing
        await task.do_task()
        parent_mock.assert_has_calls(
            [call.do_thing('one'), call.sleep(2), call.do_thing('two'),]
        )

This fails with the assertion:

E               AssertionError: Calls not found.
E               Expected: [call.do_thing('one'), call.sleep(2), call.do_thing('two')]
E               Actual: []

I can fix this with:

import asyncio

import pytest
from asynctest import patch, MagicMock, call

import task

@pytest.mark.asyncio
async def test_order():
    parent_mock = MagicMock()
    with patch.object(
        asyncio, 'sleep', parent=parent_mock, _new_name='sleep'
    ), patch.object(task, 'do_thing', parent=parent_mock, _new_name='do_thing'):
        await task.do_task()
        parent_mock.assert_has_calls(
            [call.do_thing('one'), call.sleep(2), call.do_thing('two'),]
        )

This looks to me like the __setattr__ isn't setting up the parent mocks correctly