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
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.