如何用pytest Patch AWS Secrets Manager的list_secrets返回值?
解决方法
问题根源
你测试代码里patch的是自己创建的secret_client对象,但待测试的list方法会重新调用boto3.client("secretsmanager")生成全新的客户端实例,两个客户端不是同一个对象,所以补丁根本没作用到目标代码上。
正确的补丁方式
方法1:Patch boto3.client返回值,复用修改后的客户端
直接patch boto3.client,让它返回你预先修改好list_secrets方法的客户端,确保待测试代码使用的是同一个实例:
def test_list(self): secret_client = boto3.client("secretsmanager") secret_client.create_secret( Name="test-secret", Tags=[{"Key": "id", "Value": "xyz"}], ) secret_client.rotate_secret( SecretId="test-secret", RotationRules={'AutomaticallyAfterDays': 30}, RotationLambdaARN=mock_rotation_lambda, RotateImmediately=True, ) # 获取原始结果并添加缺失字段 original_result = secret_client.list_secrets() original_result["SecretList"][0]['NextRotationDate'] = datetime(2024, 1, 1, tzinfo=datetime.timezone.utc) # 模拟带过滤逻辑的list_secrets方法 def mock_list_secrets(**kwargs): filtered_result = original_result.copy() # 适配待测试代码中的name过滤条件 if kwargs.get("Filters"): for filter in kwargs["Filters"]: if filter["Key"] == "name" and "test" in filter["Values"]: filtered_result["SecretList"] = [ s for s in filtered_result["SecretList"] if "test" in s["Name"] ] return filtered_result # 替换客户端的list_secrets方法 secret_client.list_secrets = mock_list_secrets # Patch boto3.client,让待测试代码用这个修改后的客户端 with patch("boto3.client", return_value=secret_client): result = sut.list() # 验证结果包含目标字段 assert "NextRotationDate" in result[0]
方法2:直接Patch SecretsManager客户端的底层方法
通过patch botocore层面的客户端方法,覆盖所有实例的list_secrets行为:
from botocore.client import SecretsManager def test_list(self): secret_client = boto3.client("secretsmanager") secret_client.create_secret( Name="test-secret", Tags=[{"Key": "id", "Value": "xyz"}], ) secret_client.rotate_secret( SecretId="test-secret", RotationRules={'AutomaticallyAfterDays': 30}, RotationLambdaARN=mock_rotation_lambda, RotateImmediately=True, ) original_result = secret_client.list_secrets() original_result["SecretList"][0]['NextRotationDate'] = datetime(2024, 1, 1, tzinfo=datetime.timezone.utc) def mock_list_secrets(self, **kwargs): result = original_result.copy() # 处理待测试代码的过滤条件 if kwargs.get("Filters"): for filter in kwargs["Filters"]: if filter["Key"] == "name" and "test" in filter["Values"]: result["SecretList"] = [ s for s in result["SecretList"] if "test" in s["Name"] ] return result with patch.object(SecretsManager.Client, "list_secrets", side_effect=mock_list_secrets): result = sut.list() assert "NextRotationDate" in result[0]
关键注意点
- 必须适配过滤参数:待测试代码传入了
name过滤条件,mock方法要对应处理,否则返回的密钥列表会不符合预期。 - 时区处理:AWS返回的
NextRotationDate是带UTC时区的datetime,建议用datetime(2024, 1, 1, tzinfo=datetime.timezone.utc)模拟,避免类型不一致的问题。
内容的提问来源于stack exchange,提问作者dsm
相关产品推荐
相关产品推荐

