必须安装pytest-django插件,仅设DJANGO_SETTINGS_MODULE无效;需用--ds指定settings模块,测试中应使用client等fixture而非手动实例化,数据库操作须标记django_db。

pytest-django 插件必须装,且不能只靠 DJANGO_SETTINGS_MODULE
不装 pytest-django 就直接跑 pytest,90% 会卡在 AppRegistryNotReady: Apps aren't loaded yet 或 ImproperlyConfigured: Requested setting DEBUG...。这不是路径写错,而是原生 pytest 根本不认识 Django 的初始化流程。
DJANGO_SETTINGS_MODULE 环境变量单独设了也没用——pytest-django 插件才是唯一能触发 django.setup() 和 app 加载的入口。必须执行:
pip install pytest-django
装完还不能立刻跑测试,下一步是让插件知道该加载哪个 settings。
--ds 是唯一有效的 Django 配置入口
--ds(即 --django-settings)是 pytest-django 识别配置的强制参数,DJANGO_SETTINGS_MODULE 在配置文件里写只是辅助,不加 --ds 就等于没配。
立即学习“Python免费学习笔记(深入)”;
- 在项目根目录(含
manage.py)建pytest.ini,内容必须包含:
[pytest] addopts = --ds=myproject.settings.test python_files = test_*.py *_test.py tests.py
其中 myproject.settings.test 必须是一个真实可 import 的模块路径,比如:
-
myproject/settings/test.py→ 模块名是myproject.settings.test - 不能写成
myproject.settings_test(除非文件名真是settings_test.py) - 这个模块里至少要确保
DATABASES指向内存 SQLite:'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'
测试文件里别手动实例化 Client,用 fixture 才对
写 self.client.get(...) 看起来熟悉,但那是 TestCase 的写法;用 pytest 函数式风格时,直接 new 一个 Client() 会导致中间件、CSRF、session 全部失效,结果常是 403/404/500,而不是逻辑错误。
正确做法是依赖 pytest-django 提供的内置 fixture:
def test_home_view(client):
response = client.get("/")
assert response.status_code == 200
这个 client fixture 已预置好测试上下文,包括:
- 自动绕过 CSRF 校验(无需
csrf_exempt) - 支持
client.login(username=...),密码哈希校验照常生效(前提是测试 settings 里没关PASSWORD_HASHERS) - 所有请求共享同一个测试数据库事务,函数结束自动回滚
别在测试里调 call_command("migrate") —— pytest-django 在 session setup 阶段已根据模型生成 schema,重复 migrate 会报 Relation "xxx" already exists。
模型测试别急着查库,小心事务隔离陷阱
写 User.objects.create(...) 后立刻 User.objects.get(...) 可能查不到,不是数据没存,而是当前事务还没提交,且 pytest-django 默认用事务级隔离(非数据库级),跨连接不可见。
更稳妥的做法:
- 用
@pytest.fixture预置数据,让 pytest 管理生命周期 - 需要验证 DB 状态时,改用
obj.refresh_from_db()而非新 query - 真要跨事务验证(比如信号触发、celery task),得显式加
@pytest.mark.django_db(transaction=True)
最容易被忽略的一点:任何在测试文件顶部就访问 Model._meta.db_table 或调用 Model.objects.all() 的代码,都会抢在 Django 配置加载前执行,直接崩在 import 阶段——把这类逻辑全挪进测试函数或 fixture 里。


















