使用moto mock AWS SSM参数失败,如何正确测试Python SSM调用代码?
问题根源
你在业务代码的模块顶层初始化了SSM客户端,当测试代码执行from handler import lambda_handler时,客户端就已经完成初始化,此时@mock_ssm装饰器还没激活,mock未拦截到这个初始化动作,因此handler实际使用的还是真实环境的SSM客户端,会调用真实的SSM接口返回线上数据。
修复方案
方案1:调整业务代码的客户端初始化时机(最推荐)
将SSM客户端初始化逻辑移到handler函数内部,保证调用handler时才初始化客户端,此时mock已经处于激活状态,可以正常拦截请求:
import boto3 def lambda_handler(event, context): client = boto3.client('ssm') return client.get_parameter(Name=event["param"], WithDecryption=True) if __name__ == '__main__': print(lambda_handler({"param": "/mypath/password"}, ""))
方案2:调整测试代码的导入顺序
如果不想修改业务代码,可以将业务模块的导入逻辑放到mock激活之后,同时记得显式调用aws_credentials fixture,保证测试环境变量生效:
import os import boto3 from moto import mock_ssm import pytest @pytest.fixture def aws_credentials(): 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" @mock_ssm def test_ssm(aws_credentials): # mock激活后再导入业务模块 from handler import lambda_handler ssm = boto3.client('ssm') ssm.put_parameter( Name="/mypath/password", Description="A test parameter", Value="this is it!", Type="SecureString" ) resp = lambda_handler({"param": "/mypath/password"}, "") assert resp["Parameter"]["Value"] == "this is it!"
其他SSM Mock替代方案
- Python内置unittest.mock:无需依赖第三方库,直接mock
boto3.client方法,自定义返回值即可完成测试:from unittest import mock def test_ssm(): with mock.patch("boto3.client") as mock_boto_client: mock_ssm_instance = mock.MagicMock() mock_ssm_instance.get_parameter.return_value = {"Parameter": {"Value": "this is it!"}} mock_boto_client.return_value = mock_ssm_instance from handler import lambda_handler resp = lambda_handler({"param": "/mypath/password"}, "") assert resp["Parameter"]["Value"] == "this is it!" - localstack:本地启动兼容AWS接口的模拟服务,请求会发送到本地服务,适合集成测试场景,更贴近真实生产环境运行逻辑。
- placebo:支持录制真实AWS接口的返回结果,后续测试直接回放录制数据,无需依赖网络和真实AWS资源。
内容的提问来源于stack exchange,提问作者Abhishek Patil
相关产品推荐
相关产品推荐

