如何使用pytest,fastapi和tortoise-orm回滚每个测试?

问题描述

我正在为一个单元编写单元测试,我使用的框架是FastAPI,ORM是陆龟,而测试模块是pytest。

我有配置文件

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

另外,我有这些测试,第一个创建新的载体。第二个,创建一个运营商,然后搜索数据库中所有现有的运营商。

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}",)
    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
    )

问题是,当我使用命令docker-compose -f Docker-compose.dev.yml exec web python -m pytest(即容器的名称 web )运行测试时,出现错误,因为已经存在broker_id和carrier_id的组合。 我想要的是针对每个测试还原数据库。我该怎么办?

解决方法

正如MrBean所说,您需要使固定装置针对每个测试而不是针对每个模块运行。

您可以这样更改范围:

@pytest.fixture(scope="function")
def test_app_with_db():
    # set up
...

或者您可以完全删除scope参数,因为它默认为function

https://docs.pytest.org/en/stable/fixture.html#scope-sharing-fixtures-across-classes-modules-packages-or-session

这是假设您确实在灯具的# teardown部分中有东西。否则,没有什么可以清除数据库的。