单独运行Pytest测试通过,批量运行时最后一个测试失败求助
问题描述
- 单独执行
test_get_own_company_info_successful(命令:pytest -k test_get_own_company_info_successful)时测试通过,但批量运行所有测试时该测试出现断言错误。 - 调整测试顺序后,
test_company_create与test_get_own_company_info_successful均失败,出现WARNING django.request:log.py:241 Bad Request: /api/auth/signup警告。 - 所有测试已添加
@pytest.mark.django_db装饰器,预期测试相互独立、测试数据库每次测试后重置,但实际存在测试间关联干扰,无法定位原因,求排查思路。
项目结构
. ├── EmployeeApp ├── accounts └── tests/ ├── accounts/ │ ├── __init__.py │ └── test_views.py ├── EmployeeApp/ │ ├── __init__.py │ └── test_views.py ├── __init__.py └── conftest.py
测试代码(tests/EmployeeApp/test_views.py)
import pytest from rest_framework.test import APIClient client = APIClient() MOCK_COMPANY_RESPONSE = {'company_name': 'Test Company', 'company_description': 'comp descr', 'company_logo': 'logo.asd'} @pytest.mark.django_db def test_get_company_list_view(register_and_login_user): token = register_and_login_user.data['token'] client.credentials(HTTP_AUTHORIZATION='Token ' + token) data = {'company_name': 'Test Company', 'company_description': 'comp descr', 'company_logo': 'logo.asd' } client.post('/api/companies', data=data, format='json') request = client.get('/api/companies/', format='json') assert len(request.data) == 1 assert request.status_code == 200 @pytest.mark.django_db def test_company_create(register_and_login_user): token = register_and_login_user.data['token'] client.credentials(HTTP_AUTHORIZATION='Token ' + token) data = {'company_name': 'Test Company', 'company_description': 'comp descr', 'company_logo': 'logo.asd' } request = client.post('/api/companies', data=data, format='json') assert request.data == {'company_name': 'Test Company', 'company_description': 'comp descr', 'company_logo': 'logo.asd'} assert request.status_code == 201 @pytest.mark.django_db def test_get_own_company_info_successful(register_and_login_user, create_company): token = register_and_login_user.data['token'] client.credentials(HTTP_AUTHORIZATION='Token ' + token) comp = create_company request = client.get('/api/companies/1/', format='json') assert request.data == MOCK_COMPANY_RESPONSE
Fixture代码(conftest.py)
import pytest from rest_framework.test import APIClient client = APIClient() @pytest.fixture def register_and_login_user(): payload = { "username": "testuser", "email": "email@mail.com", "password": "12345678" } client.post("/api/auth/signup", payload) login_response = client.post("/api/auth/login", {"email": "email@mail.com", "password": "12345678"}) return login_response @pytest.fixture def create_company(): payload = { "username": "testuser", "email": "email@mail.com", "password": "12345678" } client.post("/api/auth/signup", payload) login_response = client.post("/api/auth/login", {"email": "email@mail.com", "password": "12345678"}) token = login_response.data['token'] client.credentials(HTTP_AUTHORIZATION='Token ' + token) data = { 'company_name': 'Test Company', 'company_description': 'comp descr', 'company_logo': 'logo.asd' } request = client.post('/api/companies', data=data, format='json') return request @pytest.fixture def login(): login = client.post("/api/auth/login", {"email": "email@mail.com", "password": "12345678"}) token = login.data['token'] return client.credentials(HTTP_AUTHORIZATION='Token ' + token)
排查思路
全局APIClient实例导致状态污染
- 所有测试和fixture共用同一个全局
client = APIClient()实例,该实例会保留之前请求的状态(比如已设置的credentials、cookie等),导致测试间相互干扰。 - 解决:在每个测试函数内创建APIClient实例,或者在fixture中创建局部实例并返回,避免全局共享。比如在fixture里用
client = APIClient()代替全局定义,测试函数内也不要用全局client。
- 所有测试和fixture共用同一个全局
Fixture依赖与重复操作冲突
test_get_own_company_info_successful同时依赖register_and_login_user和create_company两个fixture,而这两个fixture都在执行注册同一个用户(email@mail.com)的操作。批量运行时,第一个fixture注册用户后,第二个fixture再执行注册就会触发重复注册的错误(Bad Request),导致后续流程失败。- 解决:
- 给fixture添加作用域控制(默认是function级,显式声明更清晰),确保每个fixture在每次测试时重新执行,但要避免重复注册同一用户。
- 动态生成唯一用户信息,比如用
uuid模块生成唯一邮箱:email = f"test_{uuid.uuid4()}@mail.com",避免重复注册冲突。
硬编码的资源ID依赖
test_get_own_company_info_successful中硬编码请求/api/companies/1/,但批量测试时,数据库中可能存在多个公司记录,ID不一定是1,或者之前的测试修改了ID为1的记录,导致断言失败。- 解决:不要硬编码ID,而是从
create_companyfixture的返回值中获取公司ID,比如request = client.get(f'/api/companies/{comp.data["id"]}/', format='json')。
数据库重置机制验证
- 虽然用了
@pytest.mark.django_db,但要确认pytest-django的数据库重置策略是否正确生效。可以在每个测试函数开头打印数据库中的用户/公司数量,验证是否每次测试前数据库都是空的。 - 检查是否有测试使用了
transaction=True或者其他会影响事务回滚的设置,导致数据库状态没有被正确重置。
- 虽然用了
Fixture执行顺序与状态残留
- 当多个fixture被同一个测试使用时,它们的执行顺序可能导致状态冲突。比如
register_and_login_user先执行,设置了client的credentials,然后create_company又修改了client的credentials,最后测试函数又重新设置,可能导致权限混乱。 - 解决:每个fixture应该使用独立的APIClient实例,或者在fixture执行完成后清理client状态(比如调用
client.credentials()清空认证信息)。
- 当多个fixture被同一个测试使用时,它们的执行顺序可能导致状态冲突。比如
内容的提问来源于stack exchange,提问作者pgun
相关产品推荐
相关产品推荐

