You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用pytest mock Secrets Manager测试Aurora密码轮换Lambda

pytest测试test_secret函数实现方案

你原有测试代码存在以下语法和逻辑错误:

  • 模块导入语法错误:导入自定义模块不需要加.py后缀,import lambda_function.py as testpass应改为import lambda_function as testpass
  • moto导入语法错误:import moto import mock_secretsmanager应改为from moto import mock_secretsmanager
  • 参数传值错误:service_client入参需要传入初始化完成的boto3 Secrets Manager客户端实例,不能直接传字符串"secretsmanager"
  • 依赖未模拟:既没有在mock的Secrets Manager中预置对应AWSPENDING阶段的测试密钥,也没有mock数据库连接逻辑,运行时既找不到对应密钥,也会尝试真实连接数据库导致失败
  • 变量重复定义:重复声明了token变量,后定义的值会覆盖前值

测试实现思路

test_secret只依赖两个外部组件,全部通过mock隔离即可实现离线单元测试:

  1. Secrets Manager服务:用moto库模拟,无需真实调用AWS接口,在mock环境中预置符合要求的测试密钥即可
  2. 数据库连接逻辑:通过pytest-mock直接patch代码中的get_connection函数,返回模拟的数据库连接对象,验证SQL执行、连接关闭等逻辑是否符合预期,不需要真实连接数据库

前置依赖安装

先安装测试需要的包:

pip install pytest moto boto3 pytest-mock

完整测试代码

import boto3
import json
import pytest
from moto import mock_secretsmanager
# 导入被测Lambda模块,注意不要加.py后缀
import lambda_function as rotation_lambda

# 测试用固定常量,全部为构造的假值,无需和真实环境一致
TEST_REGION = "us-east-1"
TEST_SECRET_ARN = "arn:aws:secretsmanager:us-east-1:123456789012:secret:test-aurora-secret-Xyz123"
TEST_TOKEN = "test-client-token-abcdef123456"
# 符合轮换Lambda要求的测试密钥结构
TEST_PENDING_CREDENTIALS = {
    "host": "test-aurora-cluster.cluster-xxx.us-east-1.rds.amazonaws.com",
    "port": 3306,
    "username": "db_admin",
    "password": "test_rotated_password_456",
    "dbname": "app_db"
}

@mock_secretsmanager
def test_test_secret_when_connection_succeed(mocker):
    # 1. 初始化mock的Secrets Manager客户端,预置AWSPENDING阶段的测试密钥
    sm_client = boto3.client("secretsmanager", region_name=TEST_REGION)
    sm_client.create_secret(Name="test-aurora-secret", ARN=TEST_SECRET_ARN)
    sm_client.put_secret_value(
        SecretId=TEST_SECRET_ARN,
        ClientRequestToken=TEST_TOKEN,
        SecretString=json.dumps(TEST_PENDING_CREDENTIALS),
        VersionStages=["AWSPENDING"]
    )

    # 2. 构造mock数据库连接对象,patch掉真实的get_connection方法
    mock_db_conn = mocker.MagicMock()
    mock_cursor = mocker.MagicMock()
    # 模拟with conn.cursor()的上下文管理器行为
    mock_db_conn.cursor.return_value.__enter__.return_value = mock_cursor
    mocker.patch.object(rotation_lambda, "get_connection", return_value=mock_db_conn)

    # 3. 调用被测函数
    rotation_lambda.test_secret(sm_client, TEST_SECRET_ARN, TEST_TOKEN)

    # 4. 断言所有逻辑符合预期
    # 验证get_connection接收到了正确的密钥参数
    rotation_lambda.get_connection.assert_called_once_with(TEST_PENDING_CREDENTIALS)
    # 验证执行了权限检查SQL
    mock_cursor.execute.assert_called_once_with("SELECT NOW()")
    mock_db_conn.commit.assert_called_once()
    # 验证连接最终被关闭
    mock_db_conn.close.assert_called_once()

@mock_secretsmanager
def test_test_secret_when_connection_failed(mocker):
    # 初始化mock SM环境,预置测试密钥
    sm_client = boto3.client("secretsmanager", region_name=TEST_REGION)
    sm_client.create_secret(Name="test-aurora-secret", ARN=TEST_SECRET_ARN)
    sm_client.put_secret_value(
        SecretId=TEST_SECRET_ARN,
        ClientRequestToken=TEST_TOKEN,
        SecretString=json.dumps(TEST_PENDING_CREDENTIALS),
        VersionStages=["AWSPENDING"]
    )

    # 模拟get_connection返回None,即数据库连接失败
    mocker.patch.object(rotation_lambda, "get_connection", return_value=None)

    # 验证函数抛出预期的ValueError
    with pytest.raises(ValueError, match=f"Unable to log into database with pending secret of secret ARN {TEST_SECRET_ARN}"):
        rotation_lambda.test_secret(sm_client, TEST_SECRET_ARN, TEST_TOKEN)

扩展测试场景

如果需要覆盖其他异常分支,只需要调整mock逻辑即可:

  • 测试密钥缺少必填字段:在put_secret_value时传入缺少host/username等字段的SecretString,断言抛出KeyError
  • 测试密钥不是合法JSON:传入非JSON格式的SecretString,断言抛出ValueError
  • 测试指定ARN/阶段的密钥不存在:不要预置对应VersionStages为AWSPENDING的密钥版本,断言抛出对应资源不存在的异常

内容的提问来源于stack exchange,提问作者BigPig89

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 12:12:22