pytest使用mark.parametrize做mocker.patch时复用前次mock数据问题
问题原因
该现象是Python可变对象的引用传递特性导致的,和pytest、mock工具的逻辑无关,属于完全符合预期的正常行为。
你定义的mock_data_1是pandas DataFrame类型,属于可变对象,两次参数化传入的都是同一个对象的内存引用。第一次测试运行时,业务代码直接在该对象上新增了列,修改了原始对象的内容,第二次测试拿到的自然就是被修改后的对象。
pytest的参数化不会自动对传入的可变对象做深拷贝,mock的return_value也只会原样返回你传入的对象,不会主动生成副本。
解决方案
不需要修改业务代码的前提下,测试侧可以通过以下几种方式解决:
- 参数化时每次传入全新的DataFrame实例,不要复用同一个可变对象:
@pytest.mark.parametrize( 'mock_arguments, arg, result', [ (pd.DataFrame({"col_1": [1,2,3]}), arg_1, output_1), (pd.DataFrame({"col_1": [1,2,3]}), arg_2, output_2) ] ) - 定义mock数据为工厂函数,每次调用返回新的实例,patch时用
side_effect动态返回副本:# 测试类内定义 def mock_data_factory(self): return pd.DataFrame({"col_1": [1,2,3]}) # 测试用例内patch修改为 mocker.patch( 'file.GetData.get_data', side_effect=lambda *args: self.mock_data_factory() ) - 将mock数据定义为函数级fixture,每次测试用例运行自动生成新实例:
@pytest.fixture(scope="function") def mock_data(self): return pd.DataFrame({"col_1": [1,2,3]})
补充说明
如果业务逻辑本身就不应该修改上游接口返回的原始数据,那在业务代码中加.copy()也是合理的优化方案,不属于为了适配测试的不合理修改。
内容的提问来源于stack exchange,提问作者somberlain
相关产品推荐
相关产品推荐

