Reputation: 71
I'm coding the unit tests for a crud, the framework I'm using is FastAPI, the ORM is tortoise and the module for testing is pytest.
I have this configuration file:
import os
import pytest
from starlette.testclient import TestClient
from tortoise.contrib.fastapi import register_tortoise
from app.config import Settings, get_settings
from app.main import create_application
def get_settings_override():
return Settings(
testing=1, database_url=os.environ.get("DATABASE_TEST_URL")
)
@pytest.fixture(scope="module")
def test_app_with_db():
# set up
app = create_application()
app.dependency_overrides[get_settings] = get_settings_override
# Link with DB for testing
register_tortoise(
app,
db_url=os.environ.get("DATABASE_TEST_URL"),
modules={"models": ["app.infra.postgres.models"]},
generate_schemas=True,
add_exception_handlers=True,
)
with TestClient(app) as test_client:
# testing
yield test_client
# tear down
Also, I have these tests, the first one creates a new carrier. The second one, creates a carrier and then searches all the existing carriers in the database.
import json
from app.infra.postgres.crud.cft import cft as pg_cft
from app.services.cft import CFTService
cft_crud = CFTService(pg_cft)
PREFIX = "/api/cft/"
def test_create_carrier(test_app_with_db):
response = test_app_with_db.post(
f"{PREFIX}",
data=json.dumps(
{
"broker_id": 1,
"carrier_id": 1,
"lower_limit": 10,
"upper_limit": 100,
"fee": 50,
"is_active": True,
}
),
)
assert response.status_code == 201
assert type(response.json()["id"]) == int
def test_get_carriers(test_app_with_db):
response = test_app_with_db.post(
f"{PREFIX}",
data=json.dumps(
{
"broker_id": 1,
"carrier_id": 1,
"lower_limit": 10,
"upper_limit": 100,
"fee": 50,
"is_active": True,
}
),
)
summary_id = response.json()["id"]
response = test_app_with_db.get(f"{PREFIX}")
assert response.status_code == 200
response_list = response.json()
assert (
len(list(filter(lambda d: d["id"] == summary_id, response_list))) == 1
)
The problem is that when I run the tests with the command docker-compose -f Docker-compose.dev.yml exec web python -m pytest
(being web the name of the container) I get an error because there is already the combination of broker_id and carrier_id.
What I want is for the database to be restored for each of the tests. How can I do that?
Edit:
That's how I managed to do what I wanted:
import os
import pytest
from starlette.testclient import TestClient
from tortoise.contrib.test import finalizer, initializer
from app.config import Settings, get_settings
from app.main import create_application
def get_settings_override():
return Settings(testing=1, database_dev_url=os.environ.get("DATABASE_TEST_URL"))
@pytest.fixture(scope="function")
def test_app():
# set up
app = create_application()
app.dependency_overrides[get_settings] = get_settings_override
with TestClient(app) as test_client:
# testing
yield test_client
# tear down
@pytest.fixture(scope="function")
def test_app_with_db():
# set up
app = create_application()
app.dependency_overrides[get_settings] = get_settings_override
# Link with DB for testing
initializer(
["app.infra.postgres.models"],
db_url=os.environ.get("DATABASE_TEST_URL"),
)
with TestClient(app) as test_client:
# testing
yield test_client
# tear down
finalizer()
Upvotes: 7
Views: 3876
Reputation: 7539
As MrBean said, you need to make the fixture run for every test, rather than for every module.
You can change the scope like this:
@pytest.fixture(scope="function")
def test_app_with_db():
# set up
...
Or you can remove the scope
parameter altogether, because it defaults to function
:
This is assuming that you actually have something in your # teardown
section of the fixture. Otherwise there's nothing to clean the database.
Upvotes: 4