Python单元测试patch类方法返回MagicMock而非预设值问题
你的mock返回值设置路径写错了。@patch 替换SecretManagerConnection类之后,传入测试用例的mock_sm是类本身的mock对象,不是类实例的mock对象。
你写的mock_sm.pull_secret().return_value = "xxx",本质是给「直接通过类调用pull_secret方法」的场景设置返回值,但你的业务代码里是先实例化类:gcp_sm = SecretManagerConnection(),再调用实例的gcp_sm.pull_secret(),走的是mock类实例的方法路径,根本没命中你设置返回值的对象,所以拿到的是默认生成的MagicMock实例。
你遇到的报错信息其实已经明确提示了调用路径:
AssertionError: assert <MagicMock name='SecretManagerConnection().pull_secret()' id='xxx'> == '预设的token值',这里的SecretManagerConnection()就代表实例化后的对象,说明你设置返回值时漏掉了实例化这一层的return_value。
有两种标准写法可以解决这个问题:
方案1:显式获取实例mock后设置返回值
mock_sm.return_value 对应类实例化后得到的实例对象mock,在这个实例mock上给pull_secret方法设返回值即可:
@patch("app.utilities.utility_functions.SecretManagerConnection") def test_fetch_token_google_secret(mock_sm): os.environ["GCP_PROJECT_ID"] = "test" # 拿到实例化后的mock对象 mock_instance = mock_sm.return_value # 给实例的pull_secret方法设置返回值 mock_instance.pull_secret.return_value = "1234567890.abcdefghijklmnopqrstuvwxyz" del os.environ["TOKEN"] assert fetch_token("test") == "1234567890.abcdefghijklmnopqrstuvwxyz"
方案2:链式调用return_value设置
unittest.mock对类mock做了属性代理,你可以直接通过链式写return_value匹配调用路径,不需要单独声明实例变量:
@patch("app.utilities.utility_functions.SecretManagerConnection") def test_fetch_token_google_secret(mock_sm): os.environ["GCP_PROJECT_ID"] = "test" # 第一个return_value对应实例化得到的对象,第二个对应pull_secret方法的返回值 mock_sm.return_value.pull_secret.return_value = "1234567890.abcdefghijklmnopqrstuvwxyz" del os.environ["TOKEN"] assert fetch_token("test") == "1234567890.abcdefghijklmnopqrstuvwxyz"
- 你之前的错误写法对应的调用场景是
SecretManagerConnection.pull_secret()(类直接绑定方法调用,不经过实例化),和业务代码的调用路径完全不匹配。 - 测试中手动修改
os.environ容易污染其他测试用例,建议用pytest的monkeypatchfixture管理环境变量,测试结束后自动回滚。
内容的提问来源于stack exchange,提问作者Dom.MB

