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

Python 3.11+中Quart应用unittest上下文共享问题的解决方法

解决Quart异步测试在Python3.11+中上下文与内存数据库共享问题

问题根源

Python3.11对IsolatedAsyncioTestCase的执行逻辑做了调整:同步的setUp方法与异步测试方法的应用上下文完全隔离,导致你在setUp中通过CLI runner初始化的内存数据库表,无法被后续异步测试方法访问,最终抛出no such table错误。此外,原代码中异步路由内的同步数据库调用也不符合Quart的异步规范,在高版本Python中会加剧上下文隔离问题。

解决方案

将所有涉及应用上下文、数据库初始化的逻辑移到异步生命周期方法中,确保初始化与测试在同一上下文内执行,同时修正异步路由的数据库调用方式:

修改后的完整代码

from os import makedirs
from os import path
from quart import Quart
from unittest import IsolatedAsyncioTestCase
from unittest import main

from db import init_app
from db import get_db
from db import init_db  # 假设db.py中存在直接初始化数据库的异步函数

def create_app(test_config=None):
    app = Quart(
        __name__,
        instance_relative_config=True,
    )
    # 直接配置共享内存数据库
    app.config.from_mapping(
        DATABASE="file::memory:?cache=shared",
    )
    if test_config is not None:
        app.config.update(test_config)
    try:
        makedirs(app.instance_path)
    except OSError:
        pass
    init_app(app)

    # 修正异步路由的数据库调用逻辑
    @app.get("/camera")
    async def list_cameras():
        db = await get_db()  # 异步获取数据库连接
        result = await db.execute("SELECT * FROM camera")
        rows = await result.fetchall()
        return list(map(dict, rows)), 200
 
    return app


class TestApp(IsolatedAsyncioTestCase):
    async def asyncSetUp(self):
        # 在异步上下文内创建应用与客户端
        self.app = create_app()
        self.client = self.app.test_client()
        
        # 推送应用上下文,确保后续操作在同一上下文内
        self.ctx = self.app.app_context()
        await self.ctx.push()
        
        # 直接调用初始化函数,替代CLI runner(避免上下文隔离)
        await init_db()

    async def asyncTearDown(self):
        # 清理上下文与数据库连接
        db = await get_db()
        await db.close()
        await self.ctx.pop()

    async def test_list_cameras(self):
        r = await self.client.get("/camera")
        self.assertEqual(r.status_code, 200)


if __name__ == "__main__":
    main()

关键改动说明

  1. 统一异步上下文初始化:将应用创建、客户端初始化、数据库初始化全部移到asyncSetUp中,确保所有操作在同一异步上下文内完成,避免Python3.11+的同步/异步上下文隔离问题。
  2. 替换CLI初始化方式:直接调用init_db函数而非CLI runner,避免CLI调用创建独立上下文导致的数据库隔离。若必须使用CLI,需改为异步调用:await self.app.test_cli_runner().invoke(args=["init-db"])。
  3. 修正异步路由的数据库调用:异步路由中必须使用异步数据库连接(如aiosqlite),通过await获取连接并执行查询,符合Quart的异步规范,同时确保上下文内连接共享。
  4. 保留共享内存数据库配置:file::memory:?cache=shared参数确保同一进程内的所有连接共享同一个内存数据库实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 21:07:09