如何在 python 中正确模拟 gcp 客户端库调用

How to correctly mock a gcp client library call in python

如何为使用 GCP 秘密管理器客户端库的函数正确编写单元测试。我一直在阅读单元测试和模拟,但我似乎无法理解这里出了什么问题。除了非常基本的单元测试之外,我从来没有真正编写过单元测试,也没有做过模拟。我在文件 main.py 中有以下 get_secret 函数,returns 一个字符串。

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 文件,我在其中尝试模拟 secretmanager。

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 类型的对象有关,它有一个 payload 类型的 google.cloud.secretmanager_v1.types.SecretPayload 对象,它是一个 data 类型的对象 bytes

任何有关如何正确执行此操作的帮助将不胜感激。

@patch("main.secretmanager") 尝试修补 secretmanager 这是一个模块,但我需要修补 secretmanager.SecretManagerServiceClient 这是一个 class,我试过这个但它是由于我在 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'