Search code examples
pythonasync-awaitpytestpython-asynciopython-3.8

Patching Async Object in Python 3.8


I have a newbie question about mock patching async object with Python 3.8. All I am trying is to mock post() so that I can test the error handling logic, but so far I have had no luck. Could you please tell me what I did wrong? Thanks a lot.

main.py

import httpx


test_data = {"id": "123"}

class DebugClass:
    def post(self):
        try:
            async with httpx.AsyncClient() as client:
                res = await client.post(url='http://localhost:8080', data=test_data)
            return "OK"
        except Exception as e:
            return "NOK"

test_main.py

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


from main import DebugClass

class TestClass:
    @mock.patch('httpx.AsyncClient.post', new_callable=AsyncMock)
    def test_post(self, mock_client_post):
        mock_client_post = AsyncMock(side_effect=TimeoutError)
        debug_class = DebugClass()
        res = debug_class.post()
        assert res == "NOK"

Solution

  • For testing asyncio code by means of pytest I would suggest you to use libs pytest-asyncio and asynctest.

    To install: pip install pytest-asyncio asynctest.

    Below is an example based on your code:

    import httpx
    import asynctest
    import pytest
    
    
    class DebugClass:
        async def post(self):
            try:
                async with httpx.AsyncClient() as client:
                    res = await client.post(url='http://localhost:8080', data=test_data)
                return "OK"
            except Exception as e:
                return "NOK"
    
    
    @pytest.mark.asyncio
    async def test_debug_class_post():
        with asynctest.patch('httpx.AsyncClient.post') as post_mock:
            post_mock.side_effect = TimeoutError
            debug_class = DebugClass()
            res = await debug_class.post()
            assert res == "NOK"