You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单独运行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)
排查思路
  1. 全局APIClient实例导致状态污染

    • 所有测试和fixture共用同一个全局client = APIClient()实例,该实例会保留之前请求的状态(比如已设置的credentials、cookie等),导致测试间相互干扰。
    • 解决:在每个测试函数内创建APIClient实例,或者在fixture中创建局部实例并返回,避免全局共享。比如在fixture里用client = APIClient()代替全局定义,测试函数内也不要用全局client。
  2. 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",避免重复注册冲突。
  3. 硬编码的资源ID依赖

    • test_get_own_company_info_successful中硬编码请求/api/companies/1/,但批量测试时,数据库中可能存在多个公司记录,ID不一定是1,或者之前的测试修改了ID为1的记录,导致断言失败。
    • 解决:不要硬编码ID,而是从create_company fixture的返回值中获取公司ID,比如request = client.get(f'/api/companies/{comp.data["id"]}/', format='json')。
  4. 数据库重置机制验证

    • 虽然用了@pytest.mark.django_db,但要确认pytest-django的数据库重置策略是否正确生效。可以在每个测试函数开头打印数据库中的用户/公司数量,验证是否每次测试前数据库都是空的。
    • 检查是否有测试使用了transaction=True或者其他会影响事务回滚的设置,导致数据库状态没有被正确重置。
  5. Fixture执行顺序与状态残留

    • 当多个fixture被同一个测试使用时,它们的执行顺序可能导致状态冲突。比如register_and_login_user先执行,设置了client的credentials,然后create_company又修改了client的credentials,最后测试函数又重新设置,可能导致权限混乱。
    • 解决:每个fixture应该使用独立的APIClient实例,或者在fixture执行完成后清理client状态(比如调用client.credentials()清空认证信息)。

内容的提问来源于stack exchange,提问作者pgun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 23:50:15