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

Python单元测试使用@patch时如何控制Mock对象的合法返回值?

问题复现代码

def create(user):
    user.password = hash_function(user.password)
    db.add(user)


@patch('hash_function')
def test_create_user(hash_function):
    create(User())
    hash_function.assert_called()

问题解答

@patch是Python单元测试生态中经过大量生产验证的测试隔离工具,本身是安全的。你遇到的报错并非工具设计缺陷,而是没有对Mock对象的默认行为做符合业务逻辑的配置导致的。

被@patch替换生成的Mock对象默认行为是:无论你以什么参数调用它、访问它的任何属性,都会返回一个新的Mock实例。如果被测代码的后续逻辑会使用这个返回值做类型校验、业务逻辑处理,默认返回的Mock实例自然无法通过校验,触发报错。

你可以通过以下几种常用方式配置Mock的合法返回值,规避这类问题:

  • 直接指定固定返回值(最常用)
    如果你不需要真实执行hash_function的逻辑,只需要它返回一个符合后续校验要求的合法值,直接给Mock的return_value属性赋值即可:

    @patch('your_module.hash_function') # 注意替换为hash_function在被测文件中的实际导入路径
    def test_create_user(hash_function):
        # 配置返回符合password字段格式要求的合法值,通过db.add的参数校验
        hash_function.return_value = "valid_hashed_password_str"
        create(User())
        hash_function.assert_called()
    
  • 通过wraps参数保留原函数行为
    如果你不想手动构造返回值,希望Mock在记录调用信息(用于断言)的同时,依然执行原函数的真实逻辑返回真实结果,可以给patch传入wraps参数指向原函数:

    @patch('your_module.hash_function', wraps=hash_function)
    def test_create_user(hash_function):
        create(User())
        # 依然可以正常做调用断言
        hash_function.assert_called()
    

    这种写法下hash_function会真实运行返回合法的哈希值,完全不会触发db.add的参数校验错误。

  • 通过side_effect实现自定义逻辑
    如果你需要在Mock中自定义入参校验、动态返回值逻辑,可以给side_effect传入一个和原函数签名一致的函数,Mock被调用时会执行这个自定义函数,用它的返回值作为Mock的返回结果:

    @patch('your_module.hash_function')
    def test_create_user(hash_function):
        def real_mock_hash(raw_password):
            # 可以在这里自定义入参校验逻辑
            assert isinstance(raw_password, str)
            # 返回符合要求的结果
            return f"hashed_{raw_password}"
        hash_function.side_effect = real_mock_hash
        test_user = User(password="test_raw_pwd")
        create(test_user)
        hash_function.assert_called_once_with("test_raw_pwd")
    

Mock使用注意事项

  • 做单元测试时应该完整隔离外部依赖,比如示例中的db.add属于数据库层外部依赖,本身也应该被Mock替换,这种情况下你甚至不需要关心user.password的具体值,因为Mock的db.add不会执行真实的参数校验逻辑,测试运行会更稳定。
  • 不要滥用@patch,只对当前测试用例需要隔离的、不属于当前测试单元的依赖做替换,避免Mock范围过大导致测试逻辑和真实业务逻辑偏离。
  • 配置Mock返回值时尽量贴合业务代码的参数校验规则,比如要求字符串类型就返回字符串,要求数值类型就返回对应数值,不要保留默认的Mock实例传入有严格校验的逻辑分支。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 09:03:50