5

I have two functions in module_name/app.py

async def f1(arg):
    # do something
    return arg + '1'


async def f2(arg):
    result = await f1(arg)
    return result

I try to test f2 and mock f1 using pytest and asynctest.
It only works, if I do

def sf_f1(arg):
    return 'some value'

@pytest.mark.asyncio
async def test_f2():
    with asynctest.mock.patch('module_name.app.f1', side_effect=sf_f1):
        assert 'some value' == await f2('test')

test PASSED

But, I want do to something like this

import module_name

@pytest.fixture()
def mock_f1():
    return asynctest.CoroutineMock(module_name.app.f1, side_effect=sf_f1)


@pytest.mark.asyncio
async def test_f2_2(mock_f1):
    assert 'some value' == await f2('test')

I get

   assert 'some value' == await f2('test')
   AssertionError: assert 'some value' == 'test1'
     - some value
     + test1

Why doesn't the second way work?

6
  • 2
    What isn't working? What are your desired results and what is the actual results? Commented May 16, 2017 at 14:32
  • 1
    Mock isn't work and function f1 runs. When I want to add return value or side_effect to mocked function. Commented May 16, 2017 at 14:39
  • I add side_effect function. In the first case, it works. In the second case function f2 runs, not side_effect function. Commented May 16, 2017 at 14:50
  • A MCVE would really help here, a code that shows what you are doing and then explain what you expect to happen instead. Maybe put print statements in the various functions and state which prints you expect to happen when the mock is used. Commented May 16, 2017 at 14:57
  • Sorry, for this example. I left some changes in a code and added assertion error. I hope this code is more complete and readable. Commented May 16, 2017 at 15:29

1 Answer 1

4

In your second example, in mock_f1 fixture you create a CoroutineMock object and return it. But you don't overwrite module_name.app.f1 function: Mock-like objects don't patch anything automatically.

Here is an illustrating addition to your example:

@pytest.mark.asyncio
async def test_f2_2(mock_f1):
    print('fixture value:', mock_f1)
    print('actual module_name.app.f1 function:', module_name.app.f1)
    assert 'some value' == await f2('test')

Which will print somethink like this

fixture value: <CoroutineMock spec='function' id='139756096130688'>
actual module_name.app.f1 function: <function f1 at 0x7f1b7e1139d8>

When you call f2, it uses f1 function from the module, which is not overriden.

So here is how this would work for you:

@pytest.fixture
def mock_f1(monkeypatch):
    fake_f1 = asynctest.CoroutineMock(module_name.app.f1, side_effect=sf_f1)
    monkeypatch.setattr(module_name.app, 'f1', fake_f1)
    return fake_f1

As you probably know, monkeypatch will make sure that changes are applied only while the fixture is active.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! Now it works! I only recently began to use pytest and mock, so you really helped me a lot!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.