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

如何让pytest.fixture与unittest.mock等四种测试装饰器协同工作?

问题:pytest多装饰器协同使用时报错“test_get_generator_output function has no attribute save_df_to_db”

在单元测试中尝试结合pytest.fixture、unittest.mock.patch、pytest.mark.parameterize、pytest.mark.asyncio四个装饰器,运行代码时报错test_get_generator_output function has no attribute save_df_to_db,相关代码如下:

test_constants.py

import pytest
from unittest import mock
from .test_mock import MockGenRequest

@pytest.fixture()
async def gen_request():
    request: MockGenRequest = MockGenRequest()
    return request

test_cases = [
    (
        gen_request,
        input_df,
        output_df
    ),
]

test_generator.py

from . import test_constants
import pytest
from unittest import mock
from . import evaluator

@pytest.mark.parametrize("gen_request, input_df, output_df",
                            test_constants.test_cases)
@mock.patch('utils.request.GenRequest.save_df_to_db', return_value = None)
@pytest.mark.asyncio
async def test_get_generator_ouput(mock_save_df_to_db, request, input_df, output_df):
    generator_output = evaluator.get_generator_output(
        input = input_df,
        request = request
    )
    assert "output_id" in generator_output.columns
    testing.assert_frame_equal(output_df, generator_output, check_column_order = False)

尝试过调整参数顺序但问题未解决,如何让这些装饰器协同工作?


解决方案

1. 修正测试用例中fixture的引用方式

test_constants.test_cases里直接传入gen_request fixture对象是错误的,参数化时不需要传入fixture,fixture会自动注入到测试函数中。测试用例只需要存放测试数据即可:

修改test_constants.py:

import pytest
from unittest import mock
from .test_mock import MockGenRequest

@pytest.fixture()
async def gen_request():
    request: MockGenRequest = MockGenRequest()
    return request

# 确保input_df、output_df是预先定义好的测试DataFrame对象
test_cases = [
    (input_df, output_df),
]

2. 调整装饰器顺序和参数列表

pytest装饰器的顺序直接影响参数注入顺序,需遵循以下规则:

  • @mock.patch要放在@pytest.mark.parametrize上方
  • 测试函数参数顺序:先接收mock对象,再接收fixture,最后接收参数化的测试数据
  • 避免参数名和pytest内置fixture(如request)重名,防止冲突

修改test_generator.py:

from . import test_constants
import pytest
from unittest import mock
from . import evaluator
from pandas.testing import assert_frame_equal

@mock.patch('utils.request.GenRequest.save_df_to_db', return_value=None)
@pytest.mark.parametrize("input_df, output_df", test_constants.test_cases)
@pytest.mark.asyncio
async def test_get_generator_output(mock_save_df_to_db, gen_request, input_df, output_df):
    # 如果get_generator_output是异步函数,必须加await
    generator_output = await evaluator.get_generator_output(
        input=input_df,
        request=gen_request
    )
    assert "output_id" in generator_output.columns
    assert_frame_equal(output_df, generator_output, check_column_order=False)

3. 关键注意事项

  • 异步测试中,被调用的异步函数必须用await关键字执行
  • mock.patch的目标路径必须是被测试代码实际引用的路径,而非目标函数的定义路径
  • 确保input_df和output_df是已初始化的有效DataFrame对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 11:34:58