Search code examples
pythontestingpytestpytest-mock

How to create correct mock method


I'm trying to write a unit test for my post api method.

test:

@pytest.mark.asyncio
async def test_animals_create(async_animals_client: AsyncClient, mocker):
    path = 'create'
    animal_data = {
        'nick_name': 'ASASDASD',
        'status': 1,
        'weight': 1.02,
        'sex': 1,
    }
    mock_create_obj = mocker.patch.object(
        AnimalDAO, 
        'create_obj', 
        return_value=None, 
        new_callable=mocker.AsyncMock,
    )

    response = await async_animals_client.post(
        url=f'{async_animals_client.base_url}{path}', 
        json=animal_data,
    )

    mock_create_obj.assert_called_once_with(fields=animal_data)
    assert response.status_code == status.HTTP_201_CREATED

I want to check the endpoint's operation without creating an object in the database.

Endpoint:

@router.post('/create', status_code=status.HTTP_201_CREATED)
async def create_animal(fields: AnimalsScheme):
    await AnimalDAO.create_obj(fields=fields.model_dump())

But when executing this code, my endpoint processes and creates an object in the database.

response = await async_animals_client.post(
    url=f'{async_animals_client.base_url}{path}', 
    json=animal_data,
)

How do I make a mock correctly?

with the current code, I get:

FAILED app/animal/tests/unit/test_create_animals.py::test_animals_create - AssertionError: Expected 'create_obj' to be called once. Called 0 
times.

And object create in BD.

AnimalDAO:

class AnimalDAO(BaseDAO):
    """DAO для модели Animals."""

    obj = Animals

BaseDAO:

class BaseDAO:

    obj = None

    @classmethod
    async def create_obj(cls, fields: dict) -> None:
        async with async_session() as session:
            new_obj = cls.obj(
                **fields,
            )
            session.add(new_obj)
            await session.commit()

Used version and technology:

pytest==8.3.4
pytest-asyncio==0.25.3
pytest-mock==3.14.0
httpx==0.28.1
fastapi==0.115.6
SQLAlchemy==2.0.37


Solution

  • If you are not using the mock object "without nesting decorators or with statements", you must use the start and stop attributes. See the documentation here.