【发布时间】:2020-06-15 07:22:18
【问题描述】:
我有一个用 Python 编写的非常简单的Google Cloud Function,它通过他们的 Python 库引用了 Google 的 Secret manager。
代码很简单,如下所示:
import os
from google.cloud import secretmanager
import logging
client = secretmanager.SecretManagerServiceClient()
secret_name = "my-secret"
project_id = os.environ.get('GCP_PROJECT')
resource_name = "projects/{}/secrets/{}/versions/latest".format(project_id, secret_name)
response = client.access_secret_version(resource_name)
secret_string = response.payload.data.decode('UTF-8')
def new_measures_handler(data, context):
logging.info(secret_string)
print('File: {}.'.format(data['name']))
然后我有一个简单的单元测试,它试图利用monkey patching:
import main
def test_print(capsys, monkeypatch):
# arrange
monkeypatch.setenv("GCP_PROJECT", "TestingUser")
monkeypatch.setattr(secretmanager, "SecretManagerServiceClient", lambda: 1)
name = 'test'
data = {'name': name}
# act
main.new_measures_handler(data, None)
out, err = capsys.readouterr()
#assert
assert out == 'File: {}.\n'.format(name)
环境变量的模拟一切顺利,但我无法模拟secretmanager。它继续尝试调用实际的 API。我的最终目标是模拟 secretmanager.SecretManagerServiceClient() 并使其返回一个对象,以后可以使用该对象:client.access_secret_version(resource_name)(我认为我也需要模拟)
【问题讨论】:
-
试试:
monkeypatch.setattr(main.secretmanager, "SecretManagerServiceClient", lambda: 1)。必须这样做,因为您将secretmanager导入到main的命名空间中。 -
@jordanm 我试过了,但它继续失败并出现同样的错误。尝试调用实际的 API。
-
啊,我明白了。这是因为您在顶级范围内调用
SecretManagerServiceClient()。这意味着该对象是在执行import main时创建的,即在您的猴子补丁之前。使用if __name__ == '__main__' -
@jordanm 那么,您的建议是在函数声明上方添加
if __name__ == '__main__',并将对象初始化(client = secretmanager.SecretManagerServiceClient()等)放入其中? -
是的,函数定义之上和导入之下的所有内容都应该放在那个条件块中。
标签: python unit-testing monkeypatching