如何正确地为使用GCP秘密管理器客户端库的函数编写单元测试?我一直在阅读单元测试和mock,但我似乎无法理解这里出了什么问题。除了非常基本的单元测试之外,我从来没有真正写过单元测试,也没有写过mock。我在文件main.py
中有以下get_secret
函数,它返回一个字符串。
from google.cloud import secretmanager
def get_secret(project_id,secret_name) -> str:
"""
Get secret from gcp secrets manager
"""
client = secretmanager.SecretManagerServiceClient()
request = {"name": f"projects/{project_id}/secrets/{secret_name}/versions/latest"}
response = client.access_secret_version(request)
secret_string = response.payload.data.decode("UTF-8")
return secret_string
我有以下test_main.py
文件,我试图嘲笑秘书经理。
import pytest
from unittest.mock import patch
from main import get_secret
@pytest.fixture()
def secret_string():
return 'super_secret_token'
@patch("main.secretmanager") # mock secretmanager from main.py
def test_get_secret(secretmanager,secret_string):
secretmanager.SecretManagerServiceClient().access_secret_version().return_value = secret_string
secret_string = get_secret('project_id','secret_name')
assert secret_string == 'super_secret_token'
当我运行pytest
时,AssertionError: assert <MagicMock name='secretmanager.SecretManagerServiceClient().access_secret_version().payload.data.decode()' id='4409262192'> == 'super_secret_token'
测试失败
我知道为什么,但我不完全确定。我想这是关于access_secret_version()
返回一个类型为google.cloud.secretmanager_v1.types.service.AccessSecretVersionResponse
的对象它有一个类型为google.cloud.secretmanager_v1.types.SecretPayload
的payload
对象它是一个类型为bytes
的data
对象
任何关于如何正确地做到这一点的帮助将不胜感激。
@patch("main.secretmanager")
试图修补secretmanager
,这是一个模块,但我需要修补secretmanager.SecretManagerServiceClient
,这是一个类,我曾尝试过,但它给了我错误,由于我使用的语法不正确的return_value。
@patch("main.secretmanager.SecretManagerServiceClient")
def test_get_secret(self, mock_smc):
mock_smc.return_value.access_secret_version.return_value.payload.data = b'super_secret_token'
secret_string = get_secret('project_id', 'secret_name')
assert secret_string == 'super_secret_token'
你也可以给access_secret_version()
打补丁,但是在运行测试时,当client = secretmanager.SecretManagerServiceClient()
被调用时,它会尝试用gcp进行身份验证,如果没有有效的凭据,它将失败。在运行单元测试时,最好不要使用外部服务进行身份验证。
from unittest.mock import patch
from main import get_secret
@patch("main.secretmanager.SecretManagerServiceClient.access_secret_version")
def test_get_secret(secretmanager):
secretmanager.return_value.payload.data = b'super_secret_token'
secret_string = get_secret('project_id', 'secret_name')
assert secret_string == 'super_secret_token'