如何通过pytest参数化动态传递被补丁函数测试路由函数
解决方案:参数化测试路由函数的函数调用
要实现同时测试多个输入值对应正确函数的调用,你可以结合pytest.mark.parametrize和unittest.mock通过以下两种方式实现:
方法一:用patch.multiple批量Mock函数
适合测试多个函数的场景,一次性Mock所有可能被调用的函数,再通过参数化指定每个用例要检查的目标函数。
测试代码示例
import pytest from unittest.mock import patch import app.handlers as handlers # 修正后的原路由函数 # def router(value): # actions = { # "in": in_action, # "out": out_action, # } # actions[value]() @pytest.mark.parametrize( "value, target_func_name, expected_count", [ ("in", "in_action", 1), ("out", "out_action", 1), ("invalid", None, 0), # 无效输入,无函数调用 ] ) @patch.multiple("app.handlers", in_action=None, out_action=None) def test_router(value, target_func_name, expected_count, **mocks): # 执行路由,捕获无效输入的KeyError try: handlers.router(value) except KeyError: pass if target_func_name: # 获取对应Mock对象并断言调用次数 mock_func = mocks[target_func_name] assert mock_func.call_count == expected_count else: # 无效输入时,确保所有Mock函数都未被调用 for mock in mocks.values(): assert mock.call_count == 0
方法二:逐个Mock函数,动态获取Mock对象
如果需要测试的函数数量较少,可以逐个添加@patch装饰器,再通过参数化指定要检查的Mock对象名称。
测试代码示例
import pytest from unittest.mock import patch import app.handlers as handlers @pytest.mark.parametrize( "value, target_mock_name, expected_count", [ ("in", "mock_in_action", 1), ("out", "mock_out_action", 1), ("invalid", None, 0), ] ) @patch("app.handlers.in_action") @patch("app.handlers.out_action") def test_router(mock_out_action, mock_in_action, value, target_mock_name, expected_count): try: handlers.router(value) except KeyError: pass if target_mock_name: # 通过局部变量获取对应Mock对象 mock_func = locals()[target_mock_name] assert mock_func.call_count == expected_count else: # 验证所有Mock函数都未被调用 assert mock_in_action.call_count == 0 assert mock_out_action.call_count == 0
关键说明
- 处理无效输入:当传入
actions中不存在的value时,router会抛出KeyError,需要捕获该异常避免测试失败。 - 动态Mock对象获取:两种方法都通过参数化指定要检查的目标,避免为每个函数单独编写测试用例,提高代码复用性。
- 调用次数断言:无论是单个函数还是所有函数,都能精确验证是否被正确调用。
内容的提问来源于stack exchange,提问作者Sinnie
相关产品推荐
相关产品推荐

