pytest-django测试修改数据库被回滚,求解决方法及原理
1. @pytest.mark.django_db的默认行为
pytest-django的@pytest.mark.django_db装饰器默认会用事务包裹整个测试用例:测试开始时开启一个数据库事务,所有数据修改都在这个事务内执行;测试结束后自动回滚该事务。这种设计是为了保证测试之间的数据隔离——每个测试都能在干净的数据库环境下运行,不会影响其他测试,也不会被其他测试影响。这就是你在测试里能看到数据修改,但实际数据库里无变更的核心原因:事务回滚把所有修改都撤销了。
2. 去掉装饰器为何生效
如果去掉@pytest.mark.django_db装饰器,pytest-django不会再自动为测试创建和管理事务。此时测试代码直接运行在数据库的默认事务上下文里,数据修改会直接提交到数据库(除非你手动控制事务)。但这种方式不推荐,因为不同测试之间会互相污染数据,比如后续测试会看到之前测试留下的修改,导致测试结果不稳定。
3. @pytest.mark.django_db(transaction=True)的作用
这里的transaction=True参数会改变pytest-django的事务管理逻辑:设置该参数后,装饰器会禁用自动回滚机制,允许测试中的事务自动提交到数据库。简单来说就是告诉pytest-django“不要帮我回滚测试产生的数据变更”,所以你的修改会被持久化到实际数据库中。
关于你定义的db_no_rollback fixture
如果这个fixture的目的是禁用事务回滚,可能和@pytest.mark.django_db的默认行为冲突了——装饰器的默认事务回滚优先级更高,导致fixture的设置没有生效。而当你显式设置transaction=True时,装饰器的行为被修改,fixture的作用才能正常发挥,或者直接覆盖了回滚逻辑。
内容的提问来源于stack exchange,提问作者Tim Richardson

