如何让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
相关产品推荐
相关产品推荐

