我是AWS的初学者,并且已经创建了下面给出的第一个AWS步骤功能,现在下一步是对该步骤功能进行单元测试。现在,我卡住了lambda函数并对其进行了独立的单元测试,对此一无所知,我该如何进行阶跃函数的单元测试。
我也想到一个问题,值得对阶跃函数进行单元测试,因为它只是一个json,有时会感觉是否可以完成。
我尝试搜索,但互联网或AWS文档上没有任何线索 任何帮助将不胜感激关于此博客或任何示例用例的任何博客 谢谢
{
"Comment": "An example of the Amazon States Language using a choice state.",
"StartAt": "LoginState",
States": {
"LoginState": {
"Type": "Task",
"Resource": "arn:aws:lambda:us-east-1:170344690019:function:myfirstLogin",
"Next": "ChoiceState"
},
"ChoiceState": {
"Type" : "Choice",
"Choices": [
{
"Variable": "$.success",
"BooleanEquals": true,
"Next": "logoutState"
},
{
"Variable": "$.success",
"BooleanEquals": false,
"Next": "DefaultState"
}
],
"Default": "DefaultState"
},
"logoutState": {
"Type" : "Task",
"Resource": "arn:aws:lambda:us-east-1:170344690019:function:myFirstLogout",
"End": true
},
"DefaultState": {
"Type": "Fail",
"Error": "DefaultStateError",
"Cause": "No Matches!"
}
}
}
答案 0 :(得分:11)
这有点无聊,但会为以下解释提供帮助。在测试状态机时,您正在从单元测试的范围扩展到集成测试。
那为什么要挑剔呢?由于您正在进行集成测试,因此您将需要具有运行状态机的能力,以便可以向其提供输入并验证输出。有两种方法可以自动测试状态机...
将状态机部署到AWS帐户中的测试环境中,并使用AWS提供的任何工具(cli,boto3等)直接调用它。这更接近自动化测试,因为它可以在真实环境中测试状态机。如果将其设置为CI管道的一部分,则将要求您使用您的AWS账户中安装和执行状态机所需的访问权限来配置构建服务器。
尝试使用类似stepfunctions-local的方法在本地系统或测试环境中模拟正在运行的状态机。如果您的CI管道设置已经在运行现有的单元测试,则此选项可能很有用。这将需要一些努力才能将工具正确安装到CI环境中,但值得这样做。
我个人最喜欢的...使用localstack。这些家伙在模拟可以在Docker容器中启动并运行的多个AWS服务方面做得非常出色。如果您的lambda使用其他AWS服务,则此功能特别有用。我喜欢在CI环境中运行它以进行集成测试。
使用AWS SAM CLI。我本人并没有使用太多。它要求您使用无服务器应用程序模型。自从得到正式支持以来,他们的文档确实得到了改善,因此遵循他们的指南和大量示例应该非常容易使用。在CI环境中运行此程序将需要在测试环境中安装该工具。
我希望这会有所帮助。我认为共享此答案中的任何代码都无济于事,因为您要尝试执行的操作并不简单,并且可以通过多种方式实现。例如,CircleCI等CI服务利用Docker容器,使您可以选择生成自己的Docker容器以运行stepfunctions-local或localstack。
编辑
请参阅下面@niqui的the answer。我相信我肯定会赞成此选项在CI环境中进行测试,因为它是由AWS提供和维护的,因此它可以作为stepfunctions-local或localstack的替代方案。
答案 1 :(得分:1)
AWS最近宣布了Step Functions的可下载版本
答案 2 :(得分:0)
要在与StepFunctions Local交互期间模拟Lambda函数,一种解决方案是在测试设置启动的Python线程中创建伪造的Lambda HTTP服务,并使该服务能够解析HTTP请求URL以确定要调用的函数
我已经将此概念实现为pytest固定装置:https://github.com/chehsunliu/pytest-stepfunctions。
假设有一个状态机仅收集所有EMR群集ID,我们想在本地对其进行测试。
{
"StartAt": "ListIds",
"States": {
"ListIds": {
"Type": "Task",
"Resource": "${ListIdsLambdaArn}",
"ResultPath": "$.cluster_ids",
"End": true
}
}
}
my/pkg/emr.py
import boto3
def list_ids(*args, **kwargs):
emr_client = boto3.client("emr")
response = emr_client.list_clusters()
return [item["Id"] for item in response["Clusters"]]
tests/test_foo.py
import json
import time
from string import Template
import boto3
from botocore.stub import Stubber
def test_bar(aws_stepfunctions_endpoint_url):
# Create the definition string.
definition_template = Template("""
{
"StartAt": "ListIds",
"States": {
"ListIds": {
"Type": "Task",
"Resource": "${ListIdsLambdaArn}",
"ResultPath": "$.cluster_ids",
"End": true
}
}
}
""")
list_ids_lambda_arn = "arn:aws:lambda:us-east-1:123456789012:function:my.pkg.emr.list_ids"
definition = definition_template.safe_substitute(ListIdsLambdaArn=list_ids_lambda_arn)
# Create the state machine resource.
sfn_client = boto3.client("stepfunctions", endpoint_url=aws_stepfunctions_endpoint_url)
state_machine_arn = sfn_client.create_state_machine(
name="list-ids", definition=definition, roleArn="arn:aws:iam::012345678901:role/DummyRole"
)["stateMachineArn"]
# Mock the Lambda code.
emr_client = boto3.client("emr")
mocker.patch("my.pkg.emr.boto3", autospec=True).client.return_value = emr_client
stubber = Stubber(emr_client)
stubber.add_response(
"list_clusters", service_response={"Clusters": [{"Id": "j-00001"}, {"Id": "j-00002"}]}
)
# Start and wait until the execution finishes.
execution_arn = sfn_client.start_execution(
stateMachineArn=state_machine_arn, name="list-ids-exec", input="{}"
)["executionArn"]
with stubber:
while True:
response = sfn_client.describe_execution(executionArn=execution_arn)
if response["status"] != "RUNNING":
break
time.sleep(0.5)
# Validate the results.
stubber.assert_no_pending_responses()
assert "SUCCEEDED" == response["status"]
assert ["j-00001", "j-00002"] == json.loads(response["output"])["cluster_ids"]
安装依赖项:
$ pip install boto3 pytest pytest-stepfunctions pytest-mock
下载StepFunctions本地JAR here并执行:
$ java -jar /path/to/StepFunctionsLocal.jar \
--lambda-endpoint http://localhost:13000 \
--step-functions-endpoint http://localhost:8083 \
--wait-time-scale 0
运行测试:
$ python -m pytest -v \
--pytest-stepfunctions-endpoint-url=http://0.0.0.0:8083 \
--pytest-stepfunctions-lambda-address=0.0.0.0 \
--pytest-stepfunctions-lambda-port=13000 \
./tests
该测试也可以在Docker Compose中执行,它更易于使用和维护。您可以在我的仓库中查看自述文件。希望此装置可以帮助找到本文的人。
答案 3 :(得分:0)
我遇到了类似的问题,所以我写了一个 AWS unit tester for step functions。它通过使用官方提供的 docker 镜像来工作。
安装:
yarn add step-functions-tester
yarn add mocha chai
const TestRunner = require('step-functions-tester')
const { expect } = require('chai')
let testRunner
describe('Step function tester', function () {
this.timeout('30s')
before('Set up test runner', async function () {
testRunner = new TestRunner()
await testRunner.setUp()
})
afterEach('Clean up', async function () {
await testRunner.cleanUp()
})
after('Tear down', async function () {
await testRunner.tearDown()
})
it('Step function test', async function () {
// AWS Step Function definition
const stepFunctionDefinition = {StartAt: 'FirstStep', States: {FirstStep: { /* ... */}}}
const stepFunctionInput = {}
// Keys are function names in the step function definition, values are arrays of calls
const callStubs = {'arn:eu-west:111:mockLambda': [{result: 'First call result'}, {result: 'Second call result'}], /*... */}
const { executions } = await testRunner.run(callStubs, stepFunctionDefinition, stepFunctionInput)
expect(executions).deep.equal(expectedExecutions)
})
})