函数外定义AWS/boto3客户端/资源,单元测试认证失败求解决方案
解决方案
方法1:懒加载单例模式
将客户端初始化改为懒加载逻辑,只有第一次调用函数时才创建客户端实例。这样在测试时,mock环境已经准备完毕,客户端会使用模拟凭证创建,避免连接真实AWS。
import boto3 class SecretsManagerClient: _instance = None @classmethod def get_instance(cls): if cls._instance is None: cls._instance = boto3.client(service_name="secretsmanager") return cls._instance def get_secret_key_string(): sm_client = SecretsManagerClient.get_instance() return sm_client.get_secret_value(SecretId="my_key")["SecretString"]
方法2:测试时重置单例实例
如果使用单例模式,可在测试fixture中主动重置单例的实例,确保每次测试都基于mock环境创建新的客户端,避免残留的真实客户端影响测试。
修改后的 conftest.py:
import os import pytest from moto import mock_secretsmanager from my_module import SecretsManagerClient # 导入你的单例类 @pytest.fixture(scope="session", autouse=True) def aws_credentials(): """Mocked AWS Credentials for moto""" os.environ["AWS_ACCESS_KEY_ID"] = "testing" os.environ["AWS_SECRET_ACCESS_KEY"] = "testing" os.environ["AWS_SECURITY_TOKEN"] = "testing" os.environ["AWS_SESSION_TOKEN"] = "testing" os.environ["AWS_DEFAULT_REGION"] = "us-east-1" @pytest.fixture(scope="function") def secrets_client(aws_credentials): with mock_secretsmanager(): # 重置单例实例,确保使用mock环境创建新客户端 SecretsManagerClient._instance = None client = boto3.client("secretsmanager") client.create_secret(Name="my_key", SecretString="abcde") yield client
方法3:依赖注入模式
将客户端作为可选参数传入函数,Lambda环境下使用全局复用的客户端,测试时则传入mock的客户端。这种方式兼顾了Lambda暖启动的复用需求和测试的灵活性。
修改后的函数代码:
import boto3 # Lambda环境下复用的全局客户端 SM_CLIENT = boto3.client(service_name="secretsmanager") def get_secret_key_string(sm_client=None): # 优先使用传入的客户端,未传入则用全局客户端 client = sm_client or SM_CLIENT return client.get_secret_value(SecretId="my_key")["SecretString"]
修改后的测试代码:
from my_module import get_secret_key_string def test_get_secret_key_string(secrets_client): # 测试时传入mock的客户端 secret_string = get_secret_key_string(sm_client=secrets_client) assert secret_string == "abcde"
内容的提问来源于stack exchange,提问作者henryn
相关产品推荐
相关产品推荐

