3

This test works.

def test_mock_ingest():
    with mock.patch('app.ingest.ingest') as mock_ingest:
        app.ingest.ingest('test-data', {'test-key': 'test-value'})
        assert mock_ingest.call_count == 1

This test fails because mock_ingest.call_count = 0

def test_mock_ingest():
    with mock.patch('app.ingest.ingest') as mock_ingest:
        call_function_that_runs_async_code()
        assert mock_ingest.call_count == 1

call_function_that_runs_async_code calls the app.ingest.ingest function.

I know because I can see that the test data is ingested.

But for some reason, mock_ingest.call_count is still 0.

I think it has to do with the fact that the code that runs app.ingest.ingest is async.

Edit:

I'm using python 3.8.

I also tried this without success:

```python
def test_mock_ingest():
    with mock.patch('app.ingest.ingest', new_callable=mock.AsyncMock) as mock_ingest:
        call_function_that_runs_async_code()
        assert mock_ingest.call_count == 1
chishaku
  • 4,577
  • 3
  • 25
  • 33
  • Did you try the following? `def test_mock_ingest(): with patch.object(app.ingest, 'ingest') as mock_ingest: call_function_that_runs_async_code() mock_ingest.assert_called_once()` – Dolev Pearl Dec 21 '20 at 20:29
  • Does this answer your question? [Mocking async call in python 3.5](https://stackoverflow.com/questions/32480108/mocking-async-call-in-python-3-5) – code11 Dec 21 '20 at 20:29
  • @DolevP Yes but I read somewhere there are gotchas with that method so I'm relying on `call_count` instead. – chishaku Dec 21 '20 at 20:41
  • @code11 I tried `new_callable=mock.AsyncMock` in python 3.8 also. Will add that to my question. – chishaku Dec 21 '20 at 20:42
  • I see. My point wasn't just using `assert_called_once()` instead of `call_count`, but rather using `patch.object` instead of `patch`. – Dolev Pearl Dec 21 '20 at 20:46
  • @DolevP. Thanks, I did try that as well. I ended up figuring it out. It was a name reference issue. – chishaku Dec 21 '20 at 21:19

1 Answers1

1

The solution had nothing to do with async code after all.

call_function_that_runs_async_code wasn't calling app.ingest.ingest.

It was calling ingest after ingest was imported like this: from app.ingest import ingest.

That import is correct but due to namespace issues with mocking, importing the function in different ways across application code and test code does not work.

TIL that you patch functions where you import them, not where they are defined. https://docs.python.org/3/library/unittest.mock.html#where-to-patch

The correct solution code in my example should look like this:

def test_mock_ingest():
    with mock.patch('async_codebase.ingest') as mock_ingest:
        call_function_that_runs_async_code()
        assert mock_ingest.call_count == 1

where async_codebase includes the import:

from app.ingest import ingest
chishaku
  • 4,577
  • 3
  • 25
  • 33