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

Pytest Fixture修改另一Fixture返回实例问题问询

Pytest Fixture 共享实例导致测试失败的问题解析

问题重现

以下代码中,test_1执行通过,但test_2断言失败:

import pytest


@pytest.fixture
def new_object():
    return list()


@pytest.fixture
def a_string(new_object):
    # 修改该对象实例
    new_object.append(1)
    return "a string"


def test_1(new_object):
    assert len(new_object) == 0


def test_2(a_string, new_object):
    assert len(new_object) == 0

报错信息:

def test_2(a_string, new_object):
>       assert len(new_object) == 0
E       assert 1 == 0
E        +  where 1 = len([1])

tests/test_pytest_list.py:21: AssertionError
================================================ short test summary info =================================================
FAILED tests/test_pytest_list.py::test_2 - assert 1 == 0
============================================== 1 failed, 1 passed in 0.36s ===============================================

你疑惑的点在于:明明官方文档说fixture默认作用域是function(每个测试函数调用一次),为什么a_string里修改的new_object会影响test_2中直接引用的new_object?

核心原因

pytest的fixture默认作用域function的含义是:每个测试函数执行时,同一个fixture只会被初始化一次。也就是说,在同一个测试函数的上下文里,不管是测试函数直接引用该fixture,还是其他fixture依赖该fixture,都会复用同一个实例——pytest会对fixture实例做缓存,在当前测试函数的生命周期内只创建一次。

具体到test_2:

  1. 测试函数依赖a_string和new_object
  2. 初始化a_string时,会先初始化new_object并修改它(添加元素1)
  3. 当test_2直接引用new_object时,拿到的是已经被a_string修改过的同一个实例,因此断言失败

解决方案

如果需要每次依赖new_object都拿到全新的实例,可以改用工厂函数模式:

import pytest

@pytest.fixture
def new_object():
    # 返回一个工厂函数,每次调用都会生成新列表
    def _create_list():
        return list()
    return _create_list

@pytest.fixture
def a_string(new_object):
    # 调用工厂函数获取新实例
    obj = new_object()
    obj.append(1)
    return "a string"

def test_1(new_object):
    obj = new_object()
    assert len(obj) == 0

def test_2(a_string, new_object):
    obj = new_object()
    assert len(obj) == 0

这样,无论是a_string还是test_2,调用new_object()都会得到独立的列表实例,不会互相影响。


补充案例解析

你更新的案例同样是因为同一个测试函数内的fixture共享实例导致的问题:

@pytest.fixture
def new_object():
    """我想要测试该类的实例"""
    return list()


@pytest.fixture
def case_1(new_object):
    new_object.append(1)
    return new_object


@pytest.fixture
def case_2(new_object):
    new_object.append(2)
    return new_object


def test_cases(case_1, case_2):
    assert sum(case_1) + sum(case_2) == 3  # 失败:assert (3 + 3) == 3

在test_cases的执行上下文里,new_object只被初始化一次:

  1. 初始化case_1时,给列表添加1
  2. 初始化case_2时,给同一个列表添加2,此时列表变为[1,2]
  3. case_1和case_2指向同一个列表,sum都是3,因此断言失败

用工厂函数修复后:

import pytest

@pytest.fixture
def new_object():
    def _create_list():
        return list()
    return _create_list

@pytest.fixture
def case_1(new_object):
    obj = new_object()
    obj.append(1)
    return obj

@pytest.fixture
def case_2(new_object):
    obj = new_object()
    obj.append(2)
    return obj

def test_cases(case_1, case_2):
    assert sum(case_1) + sum(case_2) == 3  # 现在case_1是[1],case_2是[2],断言通过

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 13:40:22