如何让pytest多个测试共用同一数据库与module级fixture?
解决Django+pytest中Module级Fixture对象在多测试间不可见的问题
这问题我刚上手pytest+Django的时候也踩过一模一样的坑!你遇到的核心原因是Django测试框架的事务隔离机制:
默认情况下,pytest-django的django_db fixture会为每个测试函数单独开启一个数据库事务,测试执行完成后自动回滚,目的是保证测试之间的独立性。但你的forwarding_bot fixture是module级别的——它在所有测试的事务之外创建,第一个测试结束后回滚了自己的事务,第二个测试开启新事务时,自然看不到之前创建的Bot对象了。
解决方案:使用transactional_db共享事务
最简单的修复方式是让整个测试模块共享同一个数据库事务,这可以通过依赖pytest-django提供的transactional_db fixture实现:
import pytest from django.contrib.auth import get_user_model from bots.models import Bot @pytest.fixture(scope='module') def forwarding_bot(transactional_db): # 先创建用户,再创建Bot test_user = get_user_model().objects.create_user(username='test_user') bot, created = Bot.objects.get_or_create( name="test_bot", user=test_user, forward_http_requests_to='https://httpbin.org/post' ) return bot def test_get_bot_by_pk(forwarding_bot): print(f'test_get_bot_by_pk: bot count: {Bot.objects.count()}') # 输出1 def test_get_bot_by_uuid(forwarding_bot): print(f'test_get_bot_by_uuid: bot count: {Bot.objects.count()}') # 现在也会输出1
原理说明
transactional_db fixture会在模块级别开启一个数据库事务,所有该模块下的测试函数都在这个事务里执行。测试模块结束后,才会统一回滚事务,这样你在module级fixture里创建的Bot对象,在所有测试中都能访问到。
注意事项
- 因为所有测试共享同一个事务,如果某个测试修改了
forwarding_bot的状态(比如修改name字段),后续测试会看到修改后的状态,所以要确保测试之间没有状态依赖,或者在fixture中做必要的状态重置。 - 如果你需要更细粒度的控制,也可以考虑使用
function级别的fixture,结合@pytest.mark.django_db(transaction=True)标记,但这样就失去了module级别fixture只创建一次的优势。
内容的提问来源于stack exchange,提问作者kurtgn
相关产品推荐
相关产品推荐

