Quart: unittest framework in Python 3.11+

51 Views Asked by At

I have to the following unittest module for a Quart application API. The test module works well under Python 3.10.x. However, running under Python 3.11.x, the context seems to not be shared between setup and test methods, raising sqlite3.OperationalError: no such table: camera for each executed test method. For 3.11+ compatibility, what would the proper setup method be to ensure context (i.e. the initialized in-memory database) is shared with each asynchronous test?

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

def create_app(test_config=None):
    app = Quart(
        __name__,
        instance_relative_config=True,
    )
    app.config.from_mapping(
        DATABASE=path.join(
            app.instance_path,
            "db.sqlite",
        ),
    )
    if test_config is None:
        app.config.from_pyfile(
        "config.py",
        silent=True,
    )
    else:
        app.config.update(test_config)
    try:
        makedirs(app.instance_path)
    except OSError:
        pass
    init_app(app)

    @app.get("/camera")
    async def list_cameras():
        rows = get_db().execute(
            "SELECT * FROM camera"
        ).fetchall()
        return list(map(dict, rows)), 200
 
    return app


class TestApp(IsolatedAsyncioTestCase):
    def setUp(self):
        self.db = "file::memory:?cache=shared"
        self.app = create_app(
            {
                "DATABASE": self.db,
            }
        )
        self.client = self.app.test_client()
        runner = self.app.test_cli_runner()
        runner.invoke(args=["init-db"])

    async def asyncSetUp(self):
        self.ctx = self.app.app_context()
        await self.ctx.push()

    async def asyncTearDown(self):
        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()
0

There are 0 best solutions below