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

如何用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()

修复方案及代码调整

关键修复点

  1. 创建合法IAM角色:Moto的Lambda模拟环境会校验角色信任策略,必须创建包含lambda.amazonaws.com assume权限的角色,不能使用虚构ARN
  2. 补充Lambda必填参数:创建函数时必须指定Runtime和Handler,Moto对此有强制要求
  3. 业务代码兼容测试:允许构造函数传入外部Lambda客户端,确保测试时复用Mock环境的客户端
  4. 启用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 14:30:39