

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用 Step Functions Local 测试状态机（不支持）
<a name="sfn-local"></a>

**不支持 Step Functions Local**  
Step Functions Local 功能**并不**完备且**不受支持**。  
出于测试目的，您可以考虑使用能够模拟 Step Functions 的第三方解决方案。  
作为 Step Functions Local 的替代方案，您可以在部署到您的 AWS 账户之前使用 TestState API 对状态机逻辑进行单元测试。有关更多信息，请参阅[使用 TestState API 测试状态机](https://docs.aws.amazon.com/step-functions/latest/dg/test-state-isolation.html)。

使用 AWS Step Functions Local（Step Functions 的可下载版本），您可以使用在自己的开发环境中运行的 Step Functions 来测试应用程序。



在运行 Step Functions Local 时，您可以使用以下方法之一来调用服务集成：
+ 为 AWS Lambda 和其他服务配置本地端点。
+ 直接从 Step Functi AWS ons Local 调用服务。
+ 模拟服务集成的响应。

AWS Step Functions Local 以 JAR 包或独立的 Docker 镜像的形式提供，可在微软 Windows、Linux、macOS 和其他支持 Java 或 Docker 的平台上运行。

**警告**  
您只能使用 Step Functions Local 进行测试，切勿处理敏感信息。

**Topics**
+ [设置 Step Functions Local 和 Docker](#sfn-local-docker)
+ [设置 Step Functions Local - Java 版本](#sfn-local-jar)
+ [配置 Step Functions Local 选项](#sfn-local-config-options)
+ [运行 Step Functions Local](#sfn-local-computer)
+ [教程：使用 Step Functions 和 AWS SAM CLI Local 进行测试](sfn-local-lambda.md)
+ [使用模拟服务集成进行测试](sfn-local-test-sm-exec.md)

## 在 Docker 中设置 Step Functions Local（可下载版本）
<a name="sfn-local-docker"></a>

利用 Step Functions Local Docker 映像，您可以通过使用包含所有必要的依赖项的 Docker 映像，来快速开始使用 Step Functions Local。Docker 映像允许您在容器化工作版本中包含 Step Functions Local，将其作为持续集成测试的一部分。

要获取 Step Functions Local 的 Docker 镜像，请参阅 [https://hub.docker.com/r/amazon/ aws-stepfunctions-local](https://hub.docker.com/r/amazon/aws-stepfunctions-local)，或者输入以下 Docker 命令`pull`。

```
docker pull amazon/aws-stepfunctions-local
```

要在 Docker 上启动 Step Functions 的可下载版本，请运行以下 Docker `run`命令。

```
docker run -p 8083:8083 amazon/aws-stepfunctions-local
```

要与其他支持的服务进行交互，您需要先配置您的凭据和其他配置选项。 AWS Lambda 有关更多信息，请参阅以下主题：
+ [为 Step Functions Local 设置配置选项](#sfn-local-config-options)
+ [Docker 的凭证和配置](#docker-credentials)

## 设置 Step Functions Local（可下载版本）- Java 版本
<a name="sfn-local-jar"></a>

的可下载版本以可执行 AWS Step Functions 的 JAR 文件和 Docker 镜像的形式提供。Java 应用程序将在 Windows、Linux、macOS 和其他支持 Java 的平台上运行。除了 Java 之外，你还需要安装 AWS Command Line Interface (AWS CLI)。有关安装和配置的信息 AWS CLI，请参阅《[AWS Command Line Interface 用户指南》](https://docs.aws.amazon.com/cli/latest/userguide/)。

**在您的计算机上设置并运行 Step Functions**

1. 使用以下链接下载 Step Functions。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/step-functions/latest/dg/sfn-local.html)

1. 解压缩 `.zip` 文件。

1. 测试下载并查看版本信息。

   ```
   $ java -jar StepFunctionsLocal.jar -v
   Step Function Local
   Version: 2.0.0
   Build: 2024-05-18
   ```

1. （可选）查看可用命令的列表。

   ```
   $ java -jar StepFunctionsLocal.jar -h
   ```

1. 要在计算机上启动 Step Functions，请打开命令提示符，导航到您提取 `StepFunctionsLocal.jar` 的目录，并输入以下命令。

   ```
   java -jar StepFunctionsLocal.jar
   ```

1. 要访问本地运行的 Step Functions，请使用 `--endpoint-url` 参数。例如，使用可以按如下方式指定 Step Functions 命令： AWS CLI

   ```
   aws stepfunctions --endpoint-url http://localhost:8083 command
   ```

**注意**  
默认情况下，Step Functions Local 使用本地测试账户和凭证， AWS 区域设置为美国东部（弗吉尼亚州北部）。要将 Step Functi AWS Lambda ons Local 与其他支持的服务或其他支持的服务一起使用，您必须配置您的凭据和区域。  
如果将快速工作流与 Step Functions Local 结合使用，则执行历史记录将存储在日志文件中。它未记录到 CloudWatch 日志中。日志文件路径将基于您在创建本地状态机时提供的 CloudWatch 日志日志组 ARN。该日志文件将存储在 `/aws/states/log-group-name/${execution_arn}.log` 中，此路径相对于运行 Step Functions Local 的位置确定。例如，如果执行 ARN 为：  

```
arn:aws:states:region:account-id:express:test:example-ExpressLogGroup-wJalrXUtnFEMI
```
该日志文件将为：  

```
aws/states/log-group-name/arn:aws:states:region:account-id:express:test:example-ExpressLogGroup-wJalrXUtnFEMI.log
```

## 为 Step Functions Local 设置配置选项
<a name="sfn-local-config-options"></a>

使用 JAR 文件启动 L AWS Step Functions ocal 时，可以使用 AWS Command Line Interface (AWS CLI) 来设置配置选项，也可以将其包含在系统环境中。对于 Docker，您必须在启动 Step Functions Local 时引用的文件中指定这些选项。

### 配置选项
<a name="sfn-local-config-options-table"></a>

将 Step Functions Local 容器配置为使用 Lambda 端点和 Batch 端点等覆盖端点并调用该端点时，Step Functions Local 不会使用您指定的[凭证](#docker-credentials)。设置这些端点覆盖是可选的。


| Option | 命令行 | 环境 | 
| --- | --- | --- | 
| Account | -account, --aws-account | AWS\$1ACCOUNT\$1ID | 
| Region | -region, --aws-region | AWS\$1DEFAULT\$1区域 | 
| 等待时间比例 | -waitTimeScale, --wait-time-scale | WAIT\$1TIME\$1SCALE | 
| Lambda 端点 | -lambdaEndpoint, --lambda-endpoint | LAMBDA\$1ENDPOINT | 
| Batch 端点 | -batchEndpoint, --batch-endpoint | BATCH\$1ENDPOINT | 
| DynamoDB 端点 | -dynamo，--dynamodb 端点 DBEndpoint | DYNAMODB\$1ENDPOINT | 
| ECS 端点  | -ecsEndpoint, --ecs-endpoint | ECS\$1ENDPOINT | 
| Glue 端点 | -glueEndpoint,--glue-endpoint | GLUE\$1ENDPOINT | 
| SageMaker 端点 | -sageMakerEndpoint，--sagemaker-endpoint | SAGE\$1MAKER\$1ENDPOINT | 
| SQS 端点 | -sqsEndpoint,--sqs-endpoint | SQS\$1ENDPOINT | 
| SNS 端点 | -snsEndpoint,--sns-endpoint | SNS\$1ENDPOINT | 
| Step Functions 端点 | -stepFunctionsEndpoint, --step-functions-endpoint | STEP\$1FUNCTIONS\$1ENDPOINT | 

### Docker 的凭证和配置
<a name="docker-credentials"></a>

要为 Docker 配置 Step Functions Local，请创建以下文件：`aws-stepfunctions-local-credentials.txt`。

此文件包含您的凭证以及其他配置选项。创建 `aws-stepfunctions-local-credentials.txt` 文件时，以下内容可用作模板。

```
AWS_DEFAULT_REGION=AWS_REGION_OF_YOUR_AWS_RESOURCES
AWS_ACCESS_KEY_ID=YOUR_AWS_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=YOUR_AWS_SECRET_KEY
WAIT_TIME_SCALE=VALUE
LAMBDA_ENDPOINT=VALUE
BATCH_ENDPOINT=VALUE
DYNAMODB_ENDPOINT=VALUE
ECS_ENDPOINT=VALUE
GLUE_ENDPOINT=VALUE
SAGE_MAKER_ENDPOINT=VALUE
SQS_ENDPOINT=VALUE
SNS_ENDPOINT=VALUE
STEP_FUNCTIONS_ENDPOINT=VALUE
```

在 `aws-stepfunctions-local-credentials.txt` 中配置您的凭证和配置选项后，使用以下命令启动 Step Functions。

```
docker run -p 8083:8083 --env-file aws-stepfunctions-local-credentials.txt amazon/aws-stepfunctions-local
```

**注意**  
 建议使用特殊的 DNS 名称 `host.docker.internal`，该名称可解析为主机使用的内部 IP 地址，例如 `http://host.docker.internal:8000`。有关更多信息，请分别参阅 Mac 版 Docker 文档和 Windows 版 Docker 文档：[Networking features in Docker Desktop for Mac](https://docs.docker.com/desktop/mac/networking/#use-cases-and-workaround) 和 [Networking features in Docker Desktop for Windows](https://docs.docker.com/desktop/windows/networking/)。

## 在计算机上运行 Step Functions Local
<a name="sfn-local-computer"></a>

使用 Step Functions 的本地版本配置、开发和测试计算机上的状态机。

### 在本地运行 HelloWorld 状态机
<a name="sfn-local-heloworld"></a>

使用 AWS Command Line Interface (AWS CLI) 在本地运行 Step Functions 后，就可以开始执行状态机了。

1.  AWS CLI 通过逃避状态机定义来从中创建状态机。

   ```
   aws stepfunctions --endpoint-url http://localhost:8083 create-state-machine --definition "{\
     \"Comment\": \"A Hello World example of the Amazon States Language using a Pass state\",\
     \"StartAt\": \"HelloWorld\",\
     \"States\": {\
       \"HelloWorld\": {\
         \"Type\": \"Pass\",\
         \"End\": true\
       }\
     }}" --name "HelloWorld" --role-arn "arn:aws:iam::012345678901:role/DummyRole"
   ```
**注意**  
`role-arn` 不用于 Step Functions Local，但您必须使用正确的语法包含它。您可以使用前面示例中的 Amazon 资源名称 (ARN)。

   如果您成功创建状态机，Step Functions 将使用创建日期和状态机 ARN 做出响应。

   ```
   {
       "creationDate": 1548454198.202, 
       "stateMachineArn": "arn:aws:states:region:account-id:stateMachine:HelloWorld"
   }
   ```

1. 使用创建的状态机的 ARN 启动执行。

   ```
   aws stepfunctions --endpoint-url http://localhost:8083 start-execution --state-machine-arn arn:aws:states:region:account-id:stateMachine:HelloWorld
   ```

### Step Functions Local AWS SAM 和 CLI 本地化
<a name="with-lambda-local"></a>

您可以将 Step Functions 的本地版本与 AWS Lambda的本地版本结合使用。要对此进行配置，您必须安装和配置 AWS SAM。

有关配置和运行的信息 AWS SAM，请参阅以下内容：
+ [设置 AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-quick-start.html)
+ [在本地启动 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-local-start-lambda.html)

在您的本地系统上运行 Lambda 后，您可以启动 Step Functions Local。从提取 Step Functions 本地 JAR 文件的目录中，启动 Step Functions Local，然后使用 `--lambda-endpoint` 参数配置本地 Lambda 端点。

```
java -jar StepFunctionsLocal.jar --lambda-endpoint http://127.0.0.1:3001 command
```

有关使用运行 Step Functions Local 的更多信息 AWS Lambda，请参阅[教程：使用 Step Functions 和 AWS SAM CLI Local 测试工作流程](sfn-local-lambda.md)。

# 教程：使用 Step Functions 和 AWS SAM CLI Local 测试工作流程
<a name="sfn-local-lambda"></a>

**不支持 Step Functions Local**  
Step Functions Local 功能**并不**完备且**不受支持**。  
出于测试目的，您可以考虑使用能够模拟 Step Functions 的第三方解决方案。  
作为 Step Functions Local 的替代方案，您可以在部署到您的 AWS 账户之前使用 TestState API 对状态机逻辑进行单元测试。有关更多信息，请参阅[使用 TestState API 测试状态机](https://docs.aws.amazon.com/step-functions/latest/dg/test-state-isolation.html)。

两者 AWS Step Functions 兼而有之，在本地计算机上 AWS Lambda 运行，您无需将代码部署到即可测试状态机和 Lambda 函数。 AWS

有关更多信息，请参阅以下主题：
+ [使用 Step Functions Local 测试状态机（不支持）](sfn-local.md)
+ [设置 AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-quick-start.html)

## 第 1 步：设置 AWS SAM
<a name="install-sam"></a>

AWS Serverless Application Model (AWS SAM) CLI Local 需要安装 AWS Command Line Interface AWS SAM、和 Docker。

1. [安装 C AWS SAM LI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。
**注意**  
在安装 AWS SAM CLI 之前，你需要安装 AWS CLI 和 Docker。参见安装 AWS SAM CLI 的[先决条件](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。

1. 通读 [AWS SAM 快速入门](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-quick-start.html)文档。请务必按照以下步骤执行以下操作：

   1. [初始化应用程序](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-quick-start.html#gs-ex1-setup-local-app)

   1.  [在本地测试应用程序](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-quick-start.html#gs-ex1-test-locally) 

   

   这将创建 `sam-app` 目录，并将生成环境，其中包括基于 Python 语言的 Hello World Lambda 函数。

   

## 步骤 2：在本地测试 AWS SAM CLI
<a name="test-local-lambda"></a>

现在，您已经安装 AWS SAM 并创建了 Hello World Lambda 函数，可以测试该函数了。在 `sam-app` 目录中，输入下面的命令：

```
sam local start-api
```

这将启动 Lambda 函数的本地实例。您应该可以看到类似于如下所示的输出内容：

```
2019-01-31 16:40:27 Found credentials in shared credentials file: ~/.aws/credentials
2019-01-31 16:40:27 Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
2019-01-31 16:40:27 You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2019-01-31 16:40:27  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
```

打开浏览器并输入以下内容：

```
http://127.0.0.1:3000/hello
```

这将输出类似于以下内容的响应：

```
{"message": "hello world", "location": "72.21.198.66"}
```

按 **CTRL\$1C** 以终止 Lambda API。

## 步骤 3：启动本地 AWS SAM CLI
<a name="start-local-lambda"></a>

现在您已经测试了该功能是否有效，请启动 AWS SAM CLI Local。在 `sam-app` 目录中，输入下面的命令：

```
sam local start-lambda
```

这将启动 AWS SAM CLI Local 并提供要使用的端点，类似于以下输出：

```
2019-01-29 15:33:32 Found credentials in shared credentials file: ~/.aws/credentials
2019-01-29 15:33:32 Starting the Local Lambda Service. You can now invoke your Lambda Functions defined in your template through the endpoint.
2019-01-29 15:33:32  * Running on http://127.0.0.1:3001/ (Press CTRL+C to quit)
```

## 第 4 步：启动 Step Functions Local
<a name="start-stepfunctions-local"></a>

### JAR 文件
<a name="start-local-jar"></a>

如果使用 `.jar` 文件版本的 Step Functions Local，请启动 Step Functions 并指定 Lambda 端点。在提取 `.jar` 文件的目录中，输入以下命令：

```
java -jar StepFunctionsLocal.jar --lambda-endpoint http://localhost:3001
```

当 Step Functions Local 启动时，它将检查环境，然后检查 `~/.aws/credentials` 文件中配置的凭证。默认情况下，它开始使用虚假用户 ID，并列出为 `region us-east-1`。

```
2019-01-29 15:38:06.324: Failed to load credentials from environment because Unable to load AWS credentials from environment variables (AWS_ACCESS_KEY_ID (or AWS_ACCESS_KEY) and AWS_SECRET_KEY (or AWS_SECRET_ACCESS_KEY))
2019-01-29 15:38:06.326: Loaded credentials from profile: default
2019-01-29 15:38:06.326: Starting server on port 8083 with account account-id, region us-east-1
```

### Docker
<a name="start-local-docker"></a>

如果您使用 Docker 版本的 Step Functions Local，请使用以下命令启动 Step Functions：

```
docker run -p 8083:8083 amazon/aws-stepfunctions-local
```

有关安装 Docker 版本的 Step Functions 的信息，请参阅[在 Docker 中设置 Step Functions Local（可下载版本）](sfn-local.md#sfn-local-docker)。

**注意**  
您可以通过命令行指定端点；如果您从 `.jar` 文件启动 Step Functions，则可以通过设置环境变量来指定。对于 Docker 版本，您必须在文本文件中指定端点和凭证。请参阅[为 Step Functions Local 设置配置选项](sfn-local.md#sfn-local-config-options)。

## 步骤 5：创建引用 AWS SAM CLI 本地函数的状态机
<a name="create-local-statemachine"></a>

在 Step Functions Local 运行后，创建一个状态机，该状态机引用您在[第 1 步：设置 AWS SAM](#install-sam) 中初始化的 `HelloWorldFunction`。

```
aws stepfunctions --endpoint http://localhost:8083 create-state-machine --definition "{\
  \"Comment\": \"A Hello World example of the Amazon States Language using an AWS Lambda Local function\",\
  \"StartAt\": \"HelloWorld\",\
  \"States\": {\
    \"HelloWorld\": {\
      \"Type\": \"Task\",\
      \"Resource\": \"arn:aws:lambda:region:account-id:function:HelloWorldFunction\",\
      \"End\": true\
    }\
  }\
}\" --name "HelloWorld" --role-arn "arn:aws:iam::012345678901:role/DummyRole"
```

这将创建一个状态机，并提供一个您可以用来启动执行的 Amazon 资源名称 (ARN)。

```
{
    "creationDate": 1548805711.403, 
    "stateMachineArn": "arn:aws:states:region:account-id:stateMachine:HelloWorld"
}
```

## 第 6 步：启动本地状态机执行
<a name="run-local-statemachine"></a>

创建状态机后，启动执行。使用以下 **aws stepfunctions** 命令时，您需要引用端点和状态机 ARN：

```
aws stepfunctions --endpoint http://localhost:8083 start-execution --state-machine arn:aws:states:region:account-id:stateMachine:HelloWorld --name test
```

这将启动 `HelloWorld` 状态机的名为 `test` 的执行。

```
{
    "startDate": 1548810641.52, 
    "executionArn": "arn:aws:states:region:account-id:execution:HelloWorld:test"
}
```

现在 Step Functions 已在本地运行，你可以使用与之交互 AWS CLI。例如，要获取有关此执行的信息，请使用以下命令：

```
aws stepfunctions --endpoint http://localhost:8083 describe-execution --execution-arn arn:aws:states:region:account-id:execution:HelloWorld:test
```

请为执行调用 `describe-execution`，这可以提供更完整的详细信息，内容与下面的输出类似：

```
{
    "status": "SUCCEEDED", 
    "startDate": 1549056334.073, 
    "name": "test", 
    "executionArn": "arn:aws:states:region:account-id:execution:HelloWorld:test", 
    "stateMachineArn": "arn:aws:states:region:account-id:stateMachine:HelloWorld", 
    "stopDate": 1549056351.276, 
    "output": "{\"statusCode\": 200, \"body\": \"{\\\"message\\\": \\\"hello world\\\", \\\"location\\\": \\\"72.21.198.64\\\"}\"}", 
    "input": "{}"
}
```

# 在 Step Functions Local 中使用模拟服务集成进行测试
<a name="sfn-local-test-sm-exec"></a>

**不支持 Step Functions Local**  
Step Functions Local 功能**并不**完备且**不受支持**。  
出于测试目的，您可以考虑使用能够模拟 Step Functions 的第三方解决方案。

在 Step Functions Local 中，您可以使用模拟服务集成来测试状态机的执行路径，而无需实际调用集成服务。要将状态机配置为使用模拟服务集成，请创建一个模拟配置文件。在此文件中，您可以将服务集成的所需输出定义为模拟响应，并将使用模拟响应模拟执行路径的执行定义为测试用例。

通过向 Step Functions Local 提供模拟配置文件，您可以通过运行使用测试用例中指定模拟响应的状态机来测试服务集成调用，而无需进行实际的服务集成调用。

**注意**  
 如果您未在模拟配置文件中指定模拟服务集成响应，Step Functions Local 将使用您在设置 Step Functions Local 时配置的端点调用 AWS 服务集成。有关为 Step Functions Local 配置端点的信息，请参阅[为 Step Functions Local 设置配置选项](sfn-local.md#sfn-local-config-options)。

本主题使用以下列表中定义的几个概念：
+ 模拟服务集成 - 指配置为使用模拟响应而非执行实际服务调用的 Task 状态。
+ 模拟响应 - 指 Task 状态可以配置为使用的模拟数据。
+ 测试用例 - 指配置为使用模拟服务集成的状态机执行。
+ 模拟配置文件 - 指包含 JSON 的模拟配置文件，该文件定义了模拟服务集成、模拟响应和测试用例。

## 配置模拟服务集成
<a name="mock-resp-struct-req"></a>

您可以使用 Step Functions Local 来模拟任何服务集成。但是，Step Functions Local 并不强制模拟与真实 APIs模拟相同。模拟 Task 永远不会调用服务端点。如果您未指定模拟响应，则 Task 将尝试调用服务端点。此外，使用 `.waitForTaskToken` 模拟 Task 时，Step Functions Local 将自动生成任务令牌。

## 第 1 步：在模拟配置文件中指定模拟服务集成
<a name="create-mock-config-file"></a>

你可以使用 Step Functions Local 测试 Step Functions AWS SDK 和优化的服务集成。下图展示了在状态机定义选项卡中定义的状态机：

![\[模拟服务集成示例。\]](http://docs.aws.amazon.com/zh_cn/step-functions/latest/dg/images/msi-graph.png)


为此，您必须创建一个模拟配置文件，其中包含[模拟配置文件结构](#mock-cfg-struct)中定义的部分。

1. 创建一个名为 `MockConfigFile.json` 的文件，以便使用模拟服务集成配置测试。

   以下示例展示了一个引用状态机的模拟配置文件，该状态机有两个已定义的状态，分别名为 `LambdaState` 和 `SQSState`。

------
#### [ Mock configuration file example ]

   以下是一个模拟配置文件示例，演示了如何模拟[调用 Lambda 函数](connect-lambda.md)并[向 Amazon SQS 发送消息](connect-sqs.md)所产生的响应。在此示例中，[`LambdaSQSIntegration`](#mock-cfg-sm-sect) 状态机包含三个测试用例，分别名为 `HappyPath`、`RetryPath` 和 `HybridPath`，它们模拟名为 `LambdaState` 和 `SQSState` 的 `Task` 状态。这些状态使用 `MockedLambdaSuccess`、`MockedSQSSuccess` 和 `MockedLambdaRetry` 模拟服务响应。这些模拟服务响应在文件 `MockedResponses` 部分中定义。

   ```
   {
     "StateMachines":{
       "LambdaSQSIntegration":{
         "TestCases":{
           "HappyPath":{
             "LambdaState":"MockedLambdaSuccess",
             "SQSState":"MockedSQSSuccess"
           },
           "RetryPath":{
             "LambdaState":"MockedLambdaRetry",
             "SQSState":"MockedSQSSuccess"
           },
           "HybridPath":{
             "LambdaState":"MockedLambdaSuccess"
           }
         }
       }
     },
     "MockedResponses":{
       "MockedLambdaSuccess":{
         "0":{
           "Return":{
             "StatusCode":200,
             "Payload":{
               "StatusCode":200,
               "body":"Hello from Lambda!"
             }
           }
         }
       },
       "LambdaMockedResourceNotReady":{
         "0":{
           "Throw":{
             "Error":"Lambda.ResourceNotReadyException",
             "Cause":"Lambda resource is not ready."
           }
         }
       },
       "MockedSQSSuccess":{
         "0":{
           "Return":{
             "MD5OfMessageBody":"3bcb6e8e-7h85-4375-b0bc-1a59812c6e51",
             "MessageId":"3bcb6e8e-8b51-4375-b0bc-1a59812c6e51"
           }
         }
       },
       "MockedLambdaRetry":{
         "0":{
           "Throw":{
             "Error":"Lambda.ResourceNotReadyException",
             "Cause":"Lambda resource is not ready."
           }
         },
         "1-2":{
           "Throw":{
             "Error":"Lambda.TimeoutException",
             "Cause":"Lambda timed out."
           }
         },
         "3":{
           "Return":{
             "StatusCode":200,
             "Payload":{
               "StatusCode":200,
               "body":"Hello from Lambda!"
             }
           }
         }
       }
     }
   }
   ```

------
#### [ State machine definition ]

   下面是一个名为 `LambdaSQSIntegration` 的状态机定义示例，它定义了两个名为 `LambdaState` 和 `SQSState` 的服务集成任务状态。`LambdaState` 包含基于 `States.ALL` 的重试策略。

   ```
   {
     "Comment":"This state machine is called: LambdaSQSIntegration",
     "StartAt":"LambdaState",
     "States":{
       "LambdaState":{
         "Type":"Task",
         "Resource":"arn:aws:states:::lambda:invoke",
         "Parameters":{
           "Payload.$":"$",
           "FunctionName":"HelloWorldFunction"
         },
         "Retry":[
           {
             "ErrorEquals":[
               "States.ALL"
             ],
             "IntervalSeconds":2,
             "MaxAttempts":3,
             "BackoffRate":2
           }
         ],
         "Next":"SQSState"
       },
       "SQSState":{
         "Type":"Task",
         "Resource":"arn:aws:states:::sqs:sendMessage",
         "Parameters":{
           "QueueUrl":"https://sqs.us-east-1.amazonaws.com/account-id/myQueue",
           "MessageBody.$":"$"
         },
         "End": true
       }
     }
   }
   ```

------

   您可以使用以下测试用例之一运行模拟配置文件中引用的 `LambdaSQSIntegration` 状态机定义：
   + `HappyPath` - 该测试分别使用 `MockedLambdaSuccess` 和 `MockedSQSSuccess` 模拟 `LambdaState` 和 `SQSState` 的输出。
     + `LambdaState` 将返回以下值：

       ```
       "0":{
         "Return":{
           "StatusCode":200,
           "Payload":{
             "StatusCode":200,
             "body":"Hello from Lambda!"
           }
         }
       }
       ```
     + `SQSState` 将返回以下值：

       ```
       "0":{
         "Return":{
           "MD5OfMessageBody":"3bcb6e8e-7h85-4375-b0bc-1a59812c6e51",
           "MessageId":"3bcb6e8e-8b51-4375-b0bc-1a59812c6e51"
         }
       }
       ```
   + `RetryPath` - 该测试分别使用 `MockedLambdaRetry` 和 `MockedSQSSuccess` 模拟 `LambdaState` 和 `SQSState` 的输出。此外，`LambdaState` 被配置为执行四次重试尝试。这些尝试的模拟响应在 `MockedLambdaRetry` 状态中进行了定义和索引。
     + 原始尝试以任务失败结束，其中包含原因和错误消息，如以下示例所示：

       ```
       "0":{
         "Throw": {
           "Error": "Lambda.ResourceNotReadyException",
           "Cause": "Lambda resource is not ready."
         }
       }
       ```
     + 第一次和第二次重试都以任务失败告终，其中包含原因和错误消息，如以下示例所示：

       ```
       "1-2":{
         "Throw": {
           "Error": "Lambda.TimeoutException",
           "Cause": "Lambda timed out."
         }
       }
       ```
     + 第三次重试以任务成功结束，其中包含来自模拟 Lambda 响应中的“有效负载”部分的状态结果。

       ```
       "3":{
         "Return": {
           "StatusCode": 200,
           "Payload": {
             "StatusCode": 200,
             "body": "Hello from Lambda!"
           }
         }
       }
       ```
**注意**  
对于采用重试策略的状态，Step Functions Local 将用尽策略中设置的重试次数，直到收到成功响应。这意味着必须用连续的尝试次数来表示重试模拟，并且应该在返回成功响应之前涵盖所有的重试尝试。
如果您没有为具体的重试尝试次数指定模拟响应，例如重试 “3”，则状态机执行将失败。
   + `HybridPath` - 此测试模拟 `LambdaState` 的输出。`LambdaState` 成功运行并收到模拟数据作为响应后，`SQSState` 对生产中指定的资源执行实际服务调用。

   有关如何使用模拟服务集成开始测试执行的信息，请参阅[第 3 步：运行模拟服务集成测试](#run-mocked-serv-integ-tests)。

1. 确保模拟响应的结构符合您在调用集成服务时收到的实际服务响应的结构。有关模拟响应的结构要求信息，请参阅[配置模拟服务集成](#mock-resp-struct-req)。

   在前面的示例模拟配置文件中，`MockedLambdaSuccess` 和 `MockedLambdaRetry` 中定义的模拟响应与调用 `HelloFromLambda` 时返回的实际响应结构一致。
**重要**  
AWS 服务不同，响应结构可能会不同。Step Functions Local 不会验证模拟响应结构是否符合实际的服务响应结构。在测试之前，您必须确保模拟响应符合实际响应。要查看服务响应的结构，您可以使用 Step Functions 执行实际的服务调用，也可以查看这些服务的文档。

## 第 2 步：向 Step Functions Local 提供模拟配置文件
<a name="supply-mock-config-file"></a>

 您可以通过以下方式将模拟配置文件提供给 Step Functions Local：

------
#### [ Docker ]

**注意**  
如果您使用的是 Docker 版本的 Step Functions Local，则只能使用环境变量提供模拟配置文件。此外，在服务器初始启动时，必须将模拟配置文件挂载到 Step Functions Local 容器上。

将模拟配置文件挂载到 Step Functions Local 容器内的任何目录上。然后，设置一个名为 `SFN_MOCK_CONFIG` 的环境变量，其中包含容器中模拟配置文件的路径。此方法允许将模拟配置文件命名为任何名称，只要环境变量包含文件路径和名称即可。

以下命令展示了启动 Docker 映像的格式。

```
docker run -p 8083:8083 
--mount type=bind,readonly,source={absolute path to mock config file},destination=/home/StepFunctionsLocal/MockConfigFile.json 
-e SFN_MOCK_CONFIG="/home/StepFunctionsLocal/MockConfigFile.json" amazon/aws-stepfunctions-local
```

以下示例使用该命令启动了 Docker 映像。

```
docker run -p 8083:8083 
--mount type=bind,readonly,source=/Users/admin/Desktop/workplace/MockConfigFile.json,destination=/home/StepFunctionsLocal/MockConfigFile.json 
-e SFN_MOCK_CONFIG="/home/StepFunctionsLocal/MockConfigFile.json" amazon/aws-stepfunctions-local
```

------
#### [ JAR File ]

使用以下任一方式将模拟配置文件提供给 Step Functions Local：
+ 将模拟配置文件放在与 `Step FunctionsLocal.jar` 相同的目录中。使用此方法时，必须将模拟配置文件命名为 `MockConfigFile.json`。
+ 在运行 Step Functions Local 的会话中，将名为 `SFN_MOCK_CONFIG` 的环境变量设置为模拟配置文件的完整路径。此方法允许将模拟配置文件命名为任何名称，只要环境变量包含其文件路径和名称即可。在以下示例中，`SFN_MOCK_CONFIG` 变量设置为指向名为 `EnvSpecifiedMockConfig.json` 的模拟配置文件，文件位于 `/home/workspace` 目录中。

  ```
  export SFN_MOCK_CONFIG="/home/workspace/EnvSpecifiedMockConfig.json"
  ```

**注意**  
如果您没有向 Step Functions Local 提供环境变量 `SFN_MOCK_CONFIG`，则默认情况下，它将尝试读取在启动 Step Functions Local 的目录中名为 `MockConfigFile.json` 的模拟配置文件。
如果将模拟配置文件放在与 `Step FunctionsLocal.jar` 相同的目录中，并设置环境变量 `SFN_MOCK_CONFIG`，则 Step Functions Local 将读取由环境变量指定的文件。

------

## 第 3 步：运行模拟服务集成测试
<a name="run-mocked-serv-integ-tests"></a>

创建模拟配置文件并将其提供给 Step Functions Local 后，使用模拟服务集成运行模拟配置文件中配置的状态机。然后使用 API 操作检查执行结果。

1. 根据前面提到的[模拟配置文件](#create-mock-config-file)中的定义创建状态机。

   ```
   aws stepfunctions create-state-machine \
       --endpoint http://localhost:8083 \
       --definition "{\"Comment\":\"Thisstatemachineiscalled:LambdaSQSIntegration\",\"StartAt\":\"LambdaState\",\"States\":{\"LambdaState\":{\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::lambda:invoke\",\"Parameters\":{\"Payload.$\":\"$\",\"FunctionName\":\"arn:aws:lambda:region:account-id:function:HelloWorldFunction\"},\"Retry\":[{\"ErrorEquals\":[\"States.ALL\"],\"IntervalSeconds\":2,\"MaxAttempts\":3,\"BackoffRate\":2}],\"Next\":\"SQSState\"},\"SQSState\":{\"Type\":\"Task\",\"Resource\":\"arn:aws:states:::sqs:sendMessage\",\"Parameters\":{\"QueueUrl\":\"https://sqs.us-east-1.amazonaws.com/account-id/myQueue\",\"MessageBody.$\":\"$\"},\"End\":true}}}" \
       --name "LambdaSQSIntegration" --role-arn "arn:aws:iam::account-id:role/service-role/LambdaSQSIntegration"
   ```

1. 使用模拟服务集成运行状态机。

   要使用模拟配置文件，请在模拟配置文件中配置的状态机上进行 `[StartExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_StartExecution.html)` API 调用。为此，请在 `StartExecution` 使用的状态机 ARN 上添加后缀 `#test_name`。`test_name` 是一个测试用例，在同一个模拟配置文件中为状态机配置。

   下面的命令是一个使用 `LambdaSQSIntegration` 状态机和模拟配置的示例。在此示例中，使用[第 1 步：在模拟配置文件中指定模拟服务集成](#create-mock-config-file)中定义的 `HappyPath` 测试来执行 `LambdaSQSIntegration` 状态机。`HappyPath` 测试包含执行配置，用于处理 `LambdaState` 和 `SQSState` 状态使用 `MockedLambdaSuccess` 和 `MockedSQSSuccess` 模拟服务响应进行的模拟服务集成调用。

   ```
   aws stepfunctions start-execution \
       --endpoint http://localhost:8083 \
       --name executionWithHappyPathMockedServices \
       --state-machine arn:aws:states:region:account-id:stateMachine:LambdaSQSIntegration#HappyPath
   ```

1. 查看状态机执行响应。

   使用模拟服务集成测试调用 `StartExecution` 的响应与正常调用 `StartExecution` 的响应相同，都会返回执行 ARN 和开始日期。

   以下是使用模拟服务集成测试调用 `StartExecution` 的响应示例：

   ```
   {
      "startDate":"2022-01-28T15:03:16.981000-05:00",
      "executionArn":"arn:aws:states:region:account-id:execution:LambdaSQSIntegration:executionWithHappyPathMockedServices"
   }
   ```

1. 通过调用 `[ListExecutions](https://docs.aws.amazon.com/step-functions/latest/apireference/API_ListExecutions.html)`、`[DescribeExecution](https://docs.aws.amazon.com/step-functions/latest/apireference/API_DescribeExecution.html)` 或 `[GetExecutionHistory](https://docs.aws.amazon.com/step-functions/latest/apireference/API_GetExecutionHistory.html)` API 来检查执行结果。

   ```
   aws stepfunctions get-execution-history \
       --endpoint http://localhost:8083 \
       --execution-arn arn:aws:states:region:account-id:execution:LambdaSQSIntegration:executionWithHappyPathMockedServices
   ```

   以下示例演示了使用第 2 步所示示例响应中的执行 ARN 调用 `GetExecutionHistory` 的部分响应。在此示例中，`LambdaState` 和 `SQSState` 的输出是[模拟配置文件](#create-mock-config-file)中 `MockedLambdaSuccess` 和 `MockedSQSSuccess` 中定义的模拟数据。此外，模拟数据的使用方式与执行实际服务集成调用返回的数据相同。此外，在本示例中，`LambdaState` 的输出作为输入传递给 `SQSState`。

   ```
   {
       "events": [
           ...
           {
               "timestamp": "2021-12-02T19:39:48.988000+00:00",
               "type": "TaskStateEntered",
               "id": 2,
               "previousEventId": 0,
               "stateEnteredEventDetails": {
                   "name": "LambdaState",
                   "input": "{}",
                   "inputDetails": {
                       "truncated": false
                   }
               }
           },
           ...
           {
               "timestamp": "2021-11-25T23:39:10.587000+00:00",
               "type": "LambdaFunctionSucceeded",
               "id": 5,
               "previousEventId": 4,
               "lambdaFunctionSucceededEventDetails": {
                   "output": "{\"statusCode\":200,\"body\":\"\\\"Hello from Lambda!\\\"\"}",
                   "outputDetails": {
                       "truncated": false
                   }
               }
           },
           ...
               "timestamp": "2021-12-02T19:39:49.464000+00:00",
               "type": "TaskStateEntered",
               "id": 7,
               "previousEventId": 6,
               "stateEnteredEventDetails": {
                   "name": "SQSState",
                   "input": "{\"statusCode\":200,\"body\":\"\\\"Hello from Lambda!\\\"\"}",
                   "inputDetails": {
                       "truncated": false
                   }
               }
           },
           ...
           {
               "timestamp": "2021-11-25T23:39:10.652000+00:00",
               "type": "TaskSucceeded",
               "id": 10,
               "previousEventId": 9,
               "taskSucceededEventDetails": {
                   "resourceType": "sqs",
                   "resource": "sendMessage",
                   "output": "{\"MD5OfMessageBody\":\"3bcb6e8e-7h85-4375-b0bc-1a59812c6e51\",\"MessageId\":\"3bcb6e8e-8b51-4375-b0bc-1a59812c6e51\"}",
                   "outputDetails": {
                       "truncated": false
                   }
               }
           },
           ...
       ]
   }
   ```

## Step Functions 中模拟服务集成的配置文件
<a name="sfn-local-mock-cfg-file"></a>

**不支持 Step Functions Local**  
Step Functions Local 功能**并不**完备且**不受支持**。  
出于测试目的，您可以考虑使用能够模拟 Step Functions 的第三方解决方案。  
作为 Step Functions Local 的替代方案，您可以在部署到您的 AWS 账户之前使用 TestState API 对状态机逻辑进行单元测试。有关更多信息，请参阅[使用 TestState API 测试状态机](https://docs.aws.amazon.com/step-functions/latest/dg/test-state-isolation.html)。

要使用模拟服务集成，必须先创建一个名为 `MockConfigFile.json` 的模拟配置文件，其中包含您的模拟配置。然后将模拟配置文件提供给 Step Functions Local。此配置文件定义了测试用例，其中包含使用模拟服务集成响应的模拟状态。下一节将介绍包含模拟状态和模拟响应的模拟配置结构：

### 模拟配置文件结构
<a name="mock-cfg-struct"></a>

模拟配置是一个 JSON 对象，包含以下顶级字段：
+ `StateMachines` - 该对象的字段表示配置为使用模拟服务集成的状态机。
+ `MockedResponse` - 该对象的字段表示服务集成调用的模拟响应。

以下是一个模拟配置文件示例，其中包含 `StateMachine` 定义和 `MockedResponse`。

```
{
  "StateMachines":{
    "LambdaSQSIntegration":{
      "TestCases":{
        "HappyPath":{
          "LambdaState":"MockedLambdaSuccess",
          "SQSState":"MockedSQSSuccess"
        },
        "RetryPath":{
          "LambdaState":"MockedLambdaRetry",
          "SQSState":"MockedSQSSuccess"
        },
        "HybridPath":{
          "LambdaState":"MockedLambdaSuccess"
        }
      }
    }
  },
  "MockedResponses":{
    "MockedLambdaSuccess":{
      "0":{
        "Return":{
          "StatusCode":200,
          "Payload":{
            "StatusCode":200,
            "body":"Hello from Lambda!"
          }
        }
      }
    },
    "LambdaMockedResourceNotReady":{
      "0":{
        "Throw":{
          "Error":"Lambda.ResourceNotReadyException",
          "Cause":"Lambda resource is not ready."
        }
      }
    },
    "MockedSQSSuccess":{
      "0":{
        "Return":{
          "MD5OfMessageBody":"3bcb6e8e-7h85-4375-b0bc-1a59812c6e51",
          "MessageId":"3bcb6e8e-8b51-4375-b0bc-1a59812c6e51"
        }
      }
    },
    "MockedLambdaRetry":{
      "0":{
        "Throw":{
          "Error":"Lambda.ResourceNotReadyException",
          "Cause":"Lambda resource is not ready."
        }
      },
      "1-2":{
        "Throw":{
          "Error":"Lambda.TimeoutException",
          "Cause":"Lambda timed out."
        }
      },
      "3":{
        "Return":{
          "StatusCode":200,
          "Payload":{
            "StatusCode":200,
            "body":"Hello from Lambda!"
          }
        }
      }
    }
  }
}
```

#### 模拟配置字段参考
<a name="mock-cfg-field-ref"></a>

以下部分将说明必须在模拟配置中定义的顶层对象字段。
+ [StateMachines](#mock-cfg-sm-sect) 
+ [MockedResponses](#mock-cfg-mckd-resp-sect) 

##### StateMachines
<a name="mock-cfg-sm-sect"></a>

`StateMachines` 对象定义哪些状态机将使用模拟服务集成。每个状态机的配置都用 `StateMachines` 的顶级字段表示。字段名称是状态机的名称，值是包含名为 `TestCases` 的单个字段的对象，其字段代表该状态机的测试用例。

以下语法显示了带有两个测试用例的状态机：

```
"MyStateMachine": {
  "TestCases": {
    "HappyPath": {
      ...
    },
    "SadPath": {
      ...
    }
  }
```

##### TestCases
<a name="mock-cfg-sm-test-case"></a>

`TestCases` 字段表示状态机的各个测试用例。每个状态机的测试用例名称必须是唯一的，每个测试用例的值都是一个对象，指定了状态机中 Task 状态使用的模拟响应。

以下 `TestCase` 示例将两个 `Task` 状态与两个 `MockedResponses` 联系起来：

```
"HappyPath": {
  "SomeTaskState": "SomeMockedResponse",
  "AnotherTaskState": "AnotherMockedResponse"
}
```

##### MockedResponses
<a name="mock-cfg-mckd-resp-sect"></a>

`MockedResponses` 是一个对象，包含多个具有唯一字段名称的模拟响应对象。模拟响应对象定义了每次调用模拟 Task 状态时的成功结果或错误输出。您可以使用单个整数字符串（例如 “0”、“1”、“2” 和 “3”）或包含整数的范围（例如 “0-1”、“2-3”）来指定调用次数。

模拟 Task 时，必须为每次调用指定一个模拟响应。响应必须包含一个名为 `Return` 或 `Throw` 的单个字段，其值为模拟 Task 调用的结果或错误输出。如果未指定模拟响应，则状态机执行将失败。

下面是一个包含 `Throw` 和 `Return` 对象的 `MockedResponse` 示例。在此示例中，状态机运行的前三次返回 `"0-2"` 中指定的响应，状态机运行的第四次返回 `"3"` 中指定的响应。

```
"SomeMockedResponse": {
  "0-2": {
    "Throw": {
      ...
    }
  },
  "3": {
    "Return": {
      ...
    }
  }
}
```

**注意**  
如果使用的是 `Map` 状态，并且希望确保 `Map` 状态的响应具有可预测性，请将 `maxConcurrency` 的值设置为 1。如果您设置的值大于 1，Step Functions Local 将同时运行多次迭代，这将导致各迭代状态的整体执行顺序不可预测。这可能会进一步导致 Step Functions Local 在每次执行时对迭代状态使用不同的模拟响应。

##### Return
<a name="mock-cfg-resp-return"></a>

`Return` 表示为 `MockedResponse` 对象的一个字段。它指定了模拟 Task 状态的成功结果。

下面是一个 `Return` 对象的示例，其中包含在 Lambda 函数上调用 [https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) 时的模拟响应：

```
"Return": {
  "StatusCode": 200,
  "Payload": {
    "StatusCode": 200,
    "body": "Hello from Lambda!"
  }
}
```

##### Throw
<a name="mock-cfg-resp-throw"></a>

`Throw` 表示为 `MockedResponse` 对象的一个字段。它指定失败 Task 的[错误输出](concepts-error-handling.md)。`Throw` 的值必须是一个对象，其中包含带有字符串值的 `Error` 和 `Cause` 字段。此外，您在 `MockConfigFile.json` 中指定的 `Error` 字段的字符串值必须与状态机的 `Retry` 和 `Catch` 部分处理的错误相匹配。

下面是一个 `Throw` 对象的示例，其中包含在 Lambda 函数上调用 [https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html) 时的模拟响应：

```
"Throw": {
  "Error": "Lambda.TimeoutException",
  "Cause": "Lambda timed out."
}
```