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

如何在unittest.mock中复用带pytest fixture和参数的Mock函数?

解决pytest fixture与unittest.mock.patch.object结合的复用函数参数传递问题

我在编写单元测试时,需要结合使用pytest fixture和unittest.mock.patch.object,希望复用一个被多个测试调用的函数——这个函数既依赖pytest fixture(作为第一个参数),又需要接收额外参数。

当前尝试的代码如下:

import pandas as pd
import pytest
import os
from unittest.mock import patch

@pytest.fixture()
def rootdir():
    return os.path.dirname(os.path.abspath(__file__))

def my_mock_ret(rootdir, number):
    print(f"{rootdir}_{number}")
    return f"{rootdir}_{number}"

def test_simple(rootdir):
    a = pd.DataFrame()
    with patch.object(a, 'to_csv', lambda x: my_mock_ret(rootdir, x)) as _:
        a.to_csv(rootdir)

但这种lambda的写法无法正常工作。如果把my_mock_ret定义在测试函数内部可以正常运行,但我希望复用这个函数,不想这么做:

import pandas as pd
import pytest
import os
from unittest.mock import patch

@pytest.fixture()
def rootdir():
    return os.path.dirname(os.path.abspath(__file__))

def test_simple(rootdir):
    def my_mock_ret(number):
        print(f"{rootdir}_{number}")
        return f"{rootdir}_{number}"

    a = pd.DataFrame()
    with patch.object(a, 'to_csv', my_mock_ret) as _:
        a.to_csv(rootdir)

方法1:用functools.partial绑定fixture参数

通过functools.partial预先把fixture参数绑定到复用函数上,生成一个只接收额外参数的新函数,完美适配patch的需求:

import pandas as pd
import pytest
import os
from unittest.mock import patch
from functools import partial

@pytest.fixture()
def rootdir():
    return os.path.dirname(os.path.abspath(__file__))

def my_mock_ret(rootdir, number):
    print(f"{rootdir}_{number}")
    return f"{rootdir}_{number}"

def test_simple(rootdir):
    a = pd.DataFrame()
    # 绑定rootdir参数,生成仅需number的函数
    bound_mock = partial(my_mock_ret, rootdir)
    with patch.object(a, 'to_csv', bound_mock) as _:
        a.to_csv(rootdir)

方法2:封装为带参数的fixture

如果这个mock函数需要在多个测试中复用,可以把它封装成依赖rootdir的参数化fixture,直接在测试中调用:

import pandas as pd
import pytest
import os
from unittest.mock import patch

@pytest.fixture()
def rootdir():
    return os.path.dirname(os.path.abspath(__file__))

@pytest.fixture
def my_mock_ret_fixture(rootdir):
    def _mock(number):
        print(f"{rootdir}_{number}")
        return f"{rootdir}_{number}"
    return _mock

def test_simple(my_mock_ret_fixture, rootdir):
    a = pd.DataFrame()
    with patch.object(a, 'to_csv', my_mock_ret_fixture) as _:
        a.to_csv(rootdir)

def test_another(my_mock_ret_fixture):
    # 其他测试直接复用该fixture
    b = pd.DataFrame()
    with patch.object(b, 'to_csv', my_mock_ret_fixture) as _:
        b.to_csv("another_test_path")

方法3:修正lambda的参数兼容

如果坚持使用lambda,需要兼容pd.DataFrame.to_csv的完整参数签名(它会传递多个关键字参数),用*args接收所有位置参数即可:

def test_simple(rootdir):
    a = pd.DataFrame()
    # 用*args接收所有位置参数,取第一个作为number
    with patch.object(a, 'to_csv', lambda *args: my_mock_ret(rootdir, args[0])) as _:
        a.to_csv(rootdir)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:55:23