You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用initializer和finalizer配置FastAPI+Tortoise ORM的pytest测试报错,如何解决?

问题:FastAPI + Tortoise ORM 测试报错 asyncpg.exceptions._base.InterfaceError

按照Tortoise ORM文档编写的测试配置文件如下:

import pytest
from fastapi.testclient import TestClient
from tortoise.contrib.test import finalizer, initializer

import app.main as main
from app.core.config import settings

@pytest.fixture(scope="session", autouse=True)
def initialize_tests(request):
    db_url = "postgres://USERNAME_HERE:SECRET_PASS_HERE@127.0.0.1:5432/test"
    initializer(
        [
            "app.models",
        ],
        db_url=db_url,
        app_label="models"
    )
    print("initialize_tests")
    request.add_finaliser(finalizer)

@pytest.fixture(scope="session")
def client():
    app = main.create_application()
    with TestClient(app) as client:
        print("client")
        yield client

测试文件内容:

def test_get(client):
    response = client.get("/v1/url/")
    assert response.status_code == 200

运行测试时出现错误:

asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress

希望继续使用initializer和finalizer完成测试配置,而非手动实现的方式,请问如何解决该错误?


解决方案

1. 安装依赖

先安装pytest-asyncio,统一管理测试的异步事件循环:

pip install pytest-asyncio

2. 修改测试配置文件

将初始化fixture改为异步模式,复用测试的主事件循环,避免多循环导致的连接池冲突:

import asyncio
import pytest
import pytest_asyncio
from fastapi.testclient import TestClient
from tortoise.contrib.test import finalizer, initializer

import app.main as main

@pytest_asyncio.fixture(scope="session", autouse=True)
async def initialize_tests():
    db_url = "postgres://USERNAME_HERE:SECRET_PASS_HERE@127.0.0.1:5432/test"
    # 使用测试的主事件循环初始化Tortoise
    initializer(
        ["app.models"],
        db_url=db_url,
        app_label="models",
        loop=asyncio.get_running_loop()
    )
    yield
    # 测试会话结束后执行清理
    finalizer()

@pytest.fixture(scope="session")
def client():
    app = main.create_application()
    with TestClient(app) as client:
        yield client

3. 核心原因与说明

报错根源在于:同步的initialize_tests fixture会创建独立的事件循环初始化Tortoise,而TestClient调用异步接口时会启动另一个事件循环,两个循环共用同一个连接池就会触发并发操作冲突。

修改后的配置通过以下两点解决问题:

  • 用pytest_asyncio.fixture将初始化fixture改为异步模式,运行在测试的主事件循环中。
  • 初始化时指定loop=asyncio.get_running_loop(),强制Tortoise使用测试的主循环,确保连接池在单一循环内被使用。

内容的提问来源于stack exchange,提问作者Ming Linfeng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:36:02