Python unittest mock如何正确mock其他类的方法
问题根因
你的mock不生效是因为作用对象完全错了:
- 你在测试代码中手动实例化的
fruit = Fruit(),和Healthy.start()方法运行时内部通过Fruit()创建的实例是两个完全独立的对象 - 你给外部手动创建的实例打
start方法的mock,完全不会影响方法内部新生成的实例的执行逻辑 - 另外你的测试代码调用
healthy.start()时漏传了必填的arg位置参数,运行时会直接抛参数错误。
正确mock方案
仅使用unittest.mock内置的patch即可实现,不需要引入任何第三方工具,逻辑清晰易读。
核心规则:patch需要替换被测类所在模块中导入的外部依赖类,而不是外部依赖类本身的定义路径。比如你的Healthy类定义在jobs/healthy.py路径下,那么patch的目标路径就写jobs.healthy.Fruit,不要写jobs.fruit.Fruit。
推荐写法:装饰器形式(可读性最高)
from unittest.mock import MagicMock, patch from jobs.healthy import Healthy # patch装饰器的参数顺序和函数入参顺序是反向的,注意对应 @patch("jobs.healthy.Veggie") @patch("jobs.healthy.Fruit") def test_start_walk_fruit_logic(mock_fruit_cls, mock_veggie_cls): # 初始化被测对象,mock类自身的内部方法 healthy = Healthy() healthy.start_connection = MagicMock(return_value=1) healthy.check = MagicMock(return_value=True) # 配置Fruit类mock的行为:实例化Fruit()时返回我们自定义的mock实例 mock_fruit_ins = MagicMock() mock_fruit_ins.start.return_value = 0 mock_fruit_cls.return_value = mock_fruit_ins # 执行被测方法,传入符合Fruit分支判断的参数 test_arg = [1] # 长度为1,满足分支条件 result = healthy.start(test_arg) # 断言校验结果 assert result == 1 mock_fruit_ins.start.assert_called_once() mock_veggie_cls.assert_not_called()
备选写法:上下文管理器形式
如果只需要在局部代码段生效mock,可以用with上下文管理器包裹逻辑,避免装饰器传参:
from unittest.mock import MagicMock, patch from jobs.healthy import Healthy def test_start_walk_veggie_logic(): healthy = Healthy() healthy.start_connection = MagicMock(return_value=1) healthy.check = MagicMock(return_value=False) with patch("jobs.healthy.Fruit") as mock_fruit_cls, patch("jobs.healthy.Veggie") as mock_veggie_cls: # 配置Veggie类mock行为 mock_veggie_ins = MagicMock() mock_veggie_ins.update.return_value = None mock_veggie_cls.return_value = mock_veggie_ins # 传入走Veggie分支的参数 test_arg = [1, 2] result = healthy.start(test_arg) # 断言校验 assert result == 0 mock_veggie_ins.update.assert_called_once() mock_fruit_cls.assert_not_called()
小提示:如果需要验证方法调用时的入参是否符合预期,可以直接用mock自带的
assert_called_with方法校验,不需要额外写逻辑判断。
内容的提问来源于stack exchange,提问作者nola
相关产品推荐
相关产品推荐

