从独立的Poetry包加载pytest fixtures
我想把一些测试配置移到一个公共的Poetry包中,以避免重复使用相同的fixtures。
在一个项目中,有一个名为 user-service 的包,其中包含 tests 文件夹。就在该文件夹里,我在 user-service/tests/conftest.py 中尝试加载fixtures:
import pytest
from httpx import AsyncClient, ASGITransport
from sqlalchemy.ext.asyncio import AsyncSession
from user_service.main import app
from common.core.database import get_db
from common.tests.db_conf import ( # noqa: F401
anyio_backend,
test_engine,
setup_db,
db_session,
)
pytest_plugins = ["common.tests.db_conf"]
# Setup http client
@pytest.fixture
async def client(db_session: AsyncSession):
async def override_get_db():
yield db_session
app.dependency_overrides[get_db] = override_get_db
async with AsyncClient(
transport=ASGITransport(app=app), base_url="http://users_test"
) as ac:
yield ac
app.dependency_overrides.clear()
如你所见,我正在尝试从 common 项目加载fixtures。
common/common/tests/db_conf.py:
import os
import pytest
from sqlalchemy.ext.asyncio import (
AsyncSession,
create_async_engine,
async_sessionmaker,
AsyncEngine,
)
from sqlalchemy import NullPool
from sqlalchemy.engine import URL
from common.models.base import Model
pytest_plugins = ["anyio"]
@pytest.fixture(scope="session")
def anyio_backend():
return "asyncio"
# Setup test database engine
@pytest.fixture(scope="session")
def test_engine():
DATABASE_URL = URL.create(
drivername="postgresql+psycopg",
username=os.getenv("POSTGRES_USER"),
password=os.getenv("POSTGRES_PASSWORD"),
host=os.getenv("POSTGRES_HOST"),
port=os.getenv("POSTGRES_PORT"),
database=os.getenv("POSTGRES_DB"),
)
engine = create_async_engine(DATABASE_URL, poolclass=NullPool)
return engine
# Setup test database
@pytest.fixture(scope="session")
async def setup_db(test_engine: AsyncEngine):
async with test_engine.begin() as conn:
await conn.run_sync(Model.metadata.create_all)
yield
async with test_engine.begin() as conn:
await conn.run_sync(Model.metadata.drop_all)
await test_engine.dispose()
# Setup test database session
@pytest.fixture
async def db_session(test_engine: AsyncEngine, setup_db):
conn = await test_engine.connect()
transaction = await conn.begin()
test_async_session = async_sessionmaker(
bind=conn,
class_=AsyncSession,
expire_on_commit=False,
join_transaction_mode="create_savepoint", # data is not really saved in database so that tests are isolated
)
async with test_async_session() as session:
try:
yield session
finally:
await session.close()
await transaction.rollback()
await conn.close()
下面是我的 user-service/pyproject.toml,它加载公共包:
[tool.poetry]
name = "user-service"
version = "0.1.0"
description = ""
authors = ["Misha4231 <[email protected]>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.12"
fastapi = "^0.136.1"
ruff = "^0.15.12"
sqlalchemy = "^2.0.49"
pydantic-settings = "^2.14.0"
uvicorn = "^0.46.0"
alembic = "^1.18.4"
psycopg2-binary = "^2.9.12"
asyncpg = "^0.31.0"
structlog = "^25.5.0"
pytest = "^9.0.3"
pytest-asyncio = "^1.3.0"
pytest-mock = "^3.15.1"
httpx = "^0.28.1"
psycopg = "^3.3.3"
anyio = "^4.13.0"
common = "^0.1.1"
[tool.poetry.group.local.dependencies]
common = { path = "../common", develop = true }
[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
pythonpath = ["..", "."]
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
当我用Docker Compose运行测试时:
docker-compose -f docker-compose-test.yml run --rm users_test
每个测试都会收到一个错误,显示 db_session 未找到。
E fixture 'db_session' not found
> available fixtures: _class_scoped_runner, _function_scoped_runner, _module_scoped_runner, _package_scoped_runner, _session_scoped_runner, anyio_backend, anyio_backend_name, anyio_backend_options, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, capteesys, class_mocker, client, doctest_namespace, event_loop_policy, free_tcp_port, free_tcp_port_factory, free_udp_port, free_udp_port_factory, mocker, module_mocker, monkeypatch, package_mocker, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, session_mocker, subtests, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, unused_tcp_port, unused_tcp_port_factory, unused_udp_port, unused_udp_port_factory
> use 'pytest --fixtures [testpath]' for help on them.
如何从另一个Poetry包加载fixtures?
解决方案
问题与pytest插件无关。我在使用Docker Compose运行测试时,忘了在卷中添加包文件夹。每次运行时,代码都不是最新的,因此我以为没有什么能起作用的。
完整项目托管在公开的GitHub仓库中:https://github.com/Misha4231/two-phase-commit-fastapi/tree/main
那一行就足以从独立的Poetry包中加载fixtures:
pytest_plugins = ["common.tests.db_conf"]
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。