pytest-django更合适,因其自动处理django配置加载、数据库生命周期和事务隔离,避免手动调用django.setup()或重复写testcase;必须安装并配置django_settings_module,测试文件需符合命名规范。

pytest-django 为什么比直接用 unittest.TestCase 更合适
因为 pytest-django 自动处理了 Django 的配置加载、数据库生命周期(如创建测试库、迁移、清空)和事务隔离,避免你手动调用 django.setup() 或反复写 TestCase 类。不装它,pytest 默认根本识别不了 settings.py,跑测试会直接报 DjangoSettingNotConfigured 错误。
实操建议:
- 必须通过
pip install pytest-django安装,不能只装pytest - 在项目根目录放
pytest.ini或pyproject.toml,显式指定DJANGO_SETTINGS_MODULE,例如:[tool:pytest] DJANGO_SETTINGS_MODULE = "myproject.settings.test"
- 测试文件名必须以
test_开头或以_test.py结尾,否则pytest不自动发现
如何让测试用上真实数据库结构(而不是只靠 migrate)
pytest-django 默认使用 --keepdb 或 --create-db 控制数据库行为,但更关键的是:它默认执行 migrate 而非 syncdb —— 这意味着你的 migrations/ 必须是干净的,且不能依赖 sqlmigrate 手动执行的 SQL。
常见错误现象:测试里 MyModel.objects.create() 报 OperationalError: no such table。
原因和解决:
- 没运行
python manage.py makemigrations,导致迁移文件缺失 → 补全迁移 - 测试 settings 里
INSTALLED_APPS比正式环境少,漏了 app → 检查settings.test.py - 用了
pytest --nomigrations但又没提前建表 → 删掉该参数,或改用--migrations(默认就启用)
测试中怎么安全地操作数据库而不污染其他测试
pytest-django 默认为每个测试函数开启一个事务,并在退出时 rollback,所以你不需要手动写 TransactionTestCase。但这个机制有前提:数据库后端必须支持 savepoint(SQLite、PostgreSQL、MySQL InnoDB 都支持;MySQL MyISAM 不行)。
实操要点:
- 避免在测试里调用
transaction.commit()或transaction.set_autocommit(False),会破坏自动 rollback - 如果真要测 commit 行为(比如信号触发、外部进程读取),得用
@pytest.mark.django_db(transaction=True),此时整个测试用真实 commit,但需自己清理数据 - 批量插入慎用
bulk_create:它绕过 model 的save()方法和信号 → 如需触发post_save,得逐个save()
fixture 怎么正确注入模型实例(别再手动 new Model())
直接 MyModel(title="x") 创建对象不会走验证、不触发 __init__ 逻辑,也不进数据库。应该用 django_db fixture + model_bakery 或 factory_boy,或者最简单的:用 pytest.fixture 配合 @pytest.mark.django_db。
示例(不用第三方库):
@pytest.mark.django_db
def test_article_published():
from myapp.models import Article
article = Article.objects.create(
title="Test",
slug="test",
is_published=True
)
assert article.is_published
注意点:
- 必须加
@pytest.mark.django_db,否则Article.objects报错 - 不要在
conftest.py里定义带@pytest.mark.django_db的 fixture 并autouse=True—— 这会让所有测试都连 DB,拖慢速度 - 想复用数据?写成普通 fixture,但把
@pytest.mark.django_db放在具体测试函数上,而不是 fixture 上
最容易被忽略的是:Django 测试数据库默认用内存 SQLite,但某些 SQL 特性(如窗口函数、JSON 字段操作)不支持。一旦测试在本地过、CI 失败,先确认 CI 用的是否是和开发一致的 DB 后端 —— pytest-django 不会帮你抹平这个差异。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











