如何用moto模拟AWS Lambda?测试时遇角色报错求助
解决Moto测试AWS Lambda时的角色权限错误
问题场景
编写调用AWS Lambda的业务代码后,使用Moto进行单元测试时,创建测试Lambda函数时报错:
botocore.errorfactory.InvalidParameterValueException: An error occurred (InvalidParameterValueException) when calling the CreateFunction operation: The role defined for the function cannot be assumed by Lambda.
原业务代码
import boto3 import json class SimpleLambda: def __init__(self): self.aws_lambda = boto3.client("lambda", region_name="eu-west-2") def __call__(self): try: lambda_response = self.aws_lambda.invoke( FunctionName="test-lambda", Payload=json.dumps( { "Records": [ { "Source": "test_source", "Version": "test_version", } ] } ), ) return lambda_response["Payload"].read() except Exception as err: print(f"Could not invoke simple lambda: {err}") return None
原测试代码
import os import pytest import unittest.mock as mock import boto3 from moto import mock_lambda from aws_lambda import SimpleLambda @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" @pytest.fixture def lambda_client(aws_credentials): with mock_lambda(): yield boto3.client("lambda", region_name="eu-west-2") @pytest.fixture def lambda_test(lambda_client): lambda_client.create_function( FunctionName="test-lambda", Role="arn:aws:iam::123456789012:role/doesnotexist", Code={"ZipFile": b"test"} ) yield def test_simple_lambda_call(lambda_client, lambda_test): simple_lambda = SimpleLambda() test = simple_lambda()
修复方案及代码调整
关键修复点
- 创建合法IAM角色:Moto的Lambda模拟环境会校验角色信任策略,必须创建包含
lambda.amazonaws.comassume权限的角色,不能使用虚构ARN - 补充Lambda必填参数:创建函数时必须指定
Runtime和Handler,Moto对此有强制要求 - 业务代码兼容测试:允许构造函数传入外部Lambda客户端,确保测试时复用Mock环境的客户端
- 启用IAM Mock:导入并使用
mock_iam来模拟IAM服务,用于创建测试角色
修改后的业务代码
import boto3 import json class SimpleLambda: # 新增lambda_client参数,支持测试时传入Mock客户端 def __init__(self, lambda_client=None): self.aws_lambda = lambda_client or boto3.client("lambda", region_name="eu-west-2") def __call__(self): try: lambda_response = self.aws_lambda.invoke( FunctionName="test-lambda", Payload=json.dumps( { "Records": [ { "Source": "test_source", "Version": "test_version", } ] } ), ) return lambda_response["Payload"].read() except Exception as err: print(f"Could not invoke simple lambda: {err}") return None
修改后的测试代码
import os import pytest import boto3 from moto import mock_lambda, mock_iam from aws_lambda import SimpleLambda @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" @pytest.fixture def iam_client(aws_credentials): with mock_iam(): yield boto3.client("iam", region_name="eu-west-2") @pytest.fixture def lambda_client(aws_credentials): with mock_lambda(): yield boto3.client("lambda", region_name="eu-west-2") @pytest.fixture def lambda_test(iam_client, lambda_client): # 创建符合Lambda信任要求的IAM角色 role = iam_client.create_role( RoleName="lambda-test-role", AssumeRolePolicyDocument='{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}' ) role_arn = role["Role"]["Arn"] # 使用合法角色创建Lambda函数,补充Runtime和Handler参数 lambda_client.create_function( FunctionName="test-lambda", Role=role_arn, Code={"ZipFile": b"def handler(event, context): return {'statusCode': 200, 'body': 'test_response'}"}, Handler="lambda_function.handler", Runtime="python3.9" ) yield def test_simple_lambda_call(lambda_client, lambda_test): # 传入Mock环境的客户端,确保业务代码使用模拟资源 simple_lambda = SimpleLambda(lambda_client=lambda_client) result = simple_lambda() # 可根据实际需求添加断言 assert result is not None assert b'test_response' in result
内容的提问来源于stack exchange,提问作者cicciodevoto
相关产品推荐
相关产品推荐

