Sandhya
Sandhya

Reputation: 11

How to use aioresponses for mocking ClientSession without passing in the session as parameter

I tried using aioresponses to mock ClientSession POST request. But i get cannot connect to host sever. I am just using aiohttp client and not server. Also i do not want to pass in the fake session as a parameter to the test function. Is there a way to do this ?

Upvotes: 1

Views: 5898

Answers (1)

Dmitriy Kalekin
Dmitriy Kalekin

Reputation: 107

I think you should use aioresponses to mock the whole url of the endpoint of the remote host.

Let's suppose, that we are going to mock the external service like Telegram Bot API server. We want to test method sendMessage of our client library ClientTgBot which sends POST request.

Out project structure is like:

/app
 - __init__.py
 - client_tgbot.py
/tests/
 - __init_.py
 - conftest.py
 - test_client_tgbot_unit.py

Let's assume that our app/client_tgbot.py contains some logic, for example ClientTgBot with the method to test:

# app/client_tgbot.py
from aiohttp import ClientSession

class ClientTgBot:
    def __init__(self, token):
        self.token = token

    async def sendMessage(self, chat_id, text):
        """
        We want to test this method
        without sending POST request to the host https://api.telegram.org
        """
        url = "https://api.telegram.org/bot" + self.token + '/sendMessage'
        async with ClientSession() as c:
            response = await c.post(url, json={'chat_id': chat_id, 'text': text})
            return response

Our fixtures:

# tests/conftest.py
import pytest
from aioresponses import aioresponses
from app.client_tgbot import ClientTgBot

@pytest.fixture
def mock_aioresponse():
    with aioresponses() as m:
        yield m

@pytest.fixture(scope="module")
def tg_token():
    TEST_FAKE_TOKEN = "12345:TEST_FAKE_TOKEN"
    yield TEST_FAKE_TOKEN

@pytest.fixture(scope="module")
def client_tgbot(tg_token):
    client = ClientTgBot(tg_token)
    yield client

Our test case:

# tests/test_client_tgbot_unit.py
import pytest

@pytest.mark.asyncio
async def test_sendMessage(tg_token, client_tgbot, mock_aioresponse):
    JSON_RESPONSE_WRONG_MARKDOWN = {'ok': False, 'error_code': 400, 'description': "Bad Request: can't parse entities: Can't find end of the entity starting at byte offset 3"}
    mock_aioresponse.post(f"https://api.telegram.org/bot{tg_token}/sendMessage", payload=JSON_RESPONSE_WRONG_MARKDOWN)

    response = await client_tgbot.sendMessage(435627225, "bot_sent")

    assert response.status == 400
    assert await response.json() == JSON_RESPONSE_WRONG_MARKDOWN

Install some libs:

pip3 install aiohttp aioresponses pytest pytest-asyncio

And run your tests:

python3 -m pytest -s . -vv

As you see, we've mocked the whole url https://api.telegram.org/bot12345:TEST_FAKE_TOKEN/sendMessage without sending POST request to the real host. Also we don't have any fake session.

Upvotes: 6

Related Questions