Using mocked service integrations for testing in Step Functions Local
Step Functions Local is unsupported
Step Functions Local does not provide feature parity and is unsupported.
You might consider third party solutions that emulate Step Functions for testing purposes.
In Step Functions Local, you can test the execution paths of your state machines without actually calling integrated services by using mocked service integrations. To configure your state machines to use mocked service integrations, you create a mock configuration file. In this file, you define the desired output of your service integrations as mocked responses and the executions which use your mocked responses to simulate an execution path as test cases.
By providing the mock configuration file to Step Functions Local, you can test service integration calls by running state machines that use the mocked responses specified in the test cases instead of making actual service integration calls.
Note
If you don't specify mocked service integration responses in the mock configuration file, Step Functions Local will invoke the AWS service integration using the endpoint you configured while setting up Step Functions Local. For information about configuring endpoints for Step Functions Local, see Setting Configuration Options for Step Functions Local.
This topic uses several concepts which are defined in the following list:
Mocked Service Integrations - Refers to Task states configured to use mocked responses instead of performing actual service calls.
Mocked Responses - Refers to mock data that Task states can be configured to use.
Test Cases - Refers to state machine executions configured to use mocked service integrations.
Mock Configuration File - Refers to mock configuration file that contains JSON, which defines mocked service integrations, mocked responses, and test cases.
Configuring mocked service integrations
You can mock any service integration using Step Functions Local. However, Step Functions Local doesn’t enforce the mocks to be the same as the real APIs. A mocked Task will never call the service endpoint. If you do not specify a mocked response, a Task will attempt to call the service endpoints. In addition, Step Functions Local will automatically generate a task token when you mock a Task using the .waitForTaskToken
.
Step 1: Specify Mocked Service Integrations in a Mock Configuration File
You can test Step Functions AWS SDK and optimized service integrations using Step Functions Local. The following image shows the state machine defined in the State machine definition tab:
To do this, you must create a mock configuration file containing sections as defined in Mock configuration file structure.
-
Create a file named
MockConfigFile.json
to configure tests with mocked service integrations.The following example shows a mock configuration file referencing a state machine with two defined states named
LambdaState
andSQSState
.You can run the
LambdaSQSIntegration
state machine definition referenced in the mock configuration file using one of the following test cases:-
HappyPath
- This test mocks the output ofLambdaState
andSQSState
usingMockedLambdaSuccess
andMockedSQSSuccess
respectively.-
The
LambdaState
will return the following value:"0":{ "Return":{ "StatusCode":200, "Payload":{ "StatusCode":200, "body":"Hello from Lambda!" } } }
-
The
SQSState
will return the following value:"0":{ "Return":{ "MD5OfMessageBody":"3bcb6e8e-7h85-4375-b0bc-1a59812c6e51", "MessageId":"3bcb6e8e-8b51-4375-b0bc-1a59812c6e51" } }
-
-
RetryPath
- This test mocks the output ofLambdaState
andSQSState
usingMockedLambdaRetry
andMockedSQSSuccess
respectively. In addition,LambdaState
is configured to perform four retry attempts. The mocked responses for these attempts are defined and indexed in theMockedLambdaRetry
state.-
The initial attempt ends with a task failure containing a cause and error message as shown in the following example:
"0":{ "Throw": { "Error": "Lambda.ResourceNotReadyException", "Cause": "Lambda resource is not ready." } }
-
The first and second retry attempts end with a task failure containing a cause and error message as shown in the following example:
"1-2":{ "Throw": { "Error": "Lambda.TimeoutException", "Cause": "Lambda timed out." } }
-
The third retry attempt ends with a task success containing state result from Payload section in the mocked Lambda response.
"3":{ "Return": { "StatusCode": 200, "Payload": { "StatusCode": 200, "body": "Hello from Lambda!" } } }
Note
For states with a retry policy, Step Functions Local will exhaust the retry attempts set in the policy until it receives a success response. This means that you must denote mocks for retries with consecutive attempt numbers and should cover all the retry attempts before returning a success response.
If you do not specify a mocked response for a specific retry attempt, for example, retry "3", the state machine execution will fail.
-
-
HybridPath
- This test mocks the output ofLambdaState
. AfterLambdaState
runs successfully and receives mocked data as a response,SQSState
performs an actual service call to the resource specified in production.
For information about how to start test executions with mocked service integrations, see Step 3: Run Mocked Service Integration Tests.
-
Make sure that the mocked responses' structure conforms to the structure of actual service responses you receive when you make integrated service calls. For information about the structural requirements for mocked responses, see Configuring mocked service integrations.
In the previous example mock configuration file, the mocked responses defined in
MockedLambdaSuccess
andMockedLambdaRetry
conform to the structure of actual responses that are returned from callingHelloFromLambda
.Important
AWS service responses can vary in structure between different services. Step Functions Local doesn't validate if mocked response structures conform to actual service response structures. You must ensure that your mocked responses conform to actual responses before testing. To review the structure of service responses, you can either perform the actual service calls using Step Functions or view the documentation for those services.
Step 2: Provide the Mock Configuration File to Step Functions Local
You can provide the mock configuration file to Step Functions Local in one of the following ways:
Step 3: Run Mocked Service Integration Tests
After you create and provide a mock configuration file to Step Functions Local, run the state machine configured in the mock configuration file using mocked service integrations. Then check the execution results using an API action.
-
Create a state machine based on the previously mentioned definition in the mock configuration 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:us-east-1:123456789012: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/123456789012/myQueue\",\"MessageBody.$\":\"$\"},\"End\":true}}}" \ --name "LambdaSQSIntegration" --role-arn "arn:aws:iam::123456789012:role/service-role/LambdaSQSIntegration"
-
Run the state machine using mocked service integrations.
To use the mock configuration file, make a
StartExecution
API call on a state machine configured in the mock configuration file. To do this, append the suffix,#
, to the state machine ARN used bytest_name
StartExecution
.
is a test case, which is configured for the state machine in the same mock configuration file.test_name
The following command is an example that uses the
LambdaSQSIntegration
state machine and mock configuration. In this example, theLambdaSQSIntegration
state machine is executed using theHappyPath
test defined in Step 1: Specify Mocked Service Integrations in a Mock Configuration File. TheHappyPath
test contains the configuration for the execution to handle mock service integration calls thatLambdaState
andSQSState
states make using theMockedLambdaSuccess
andMockedSQSSuccess
mocked service responses.aws stepfunctions start-execution \ --endpoint http://localhost:8083 \ --name executionWithHappyPathMockedServices \ --state-machine arn:aws:states:us-east-1:123456789012:stateMachine:LambdaSQSIntegration#HappyPath
View the state machine execution response.
The response to calling
StartExecution
using a mocked service integration test is same as the response to callingStartExecution
normally, which returns the execution ARN and start date.The following is an example response to calling
StartExecution
using the mocked service integration test:{ "startDate":"2022-01-28T15:03:16.981000-05:00", "executionArn":"arn:aws:states:us-east-1:123456789012:execution:LambdaSQSIntegration:executionWithHappyPathMockedServices" }
Check the execution's results by making a
ListExecutions
,DescribeExecution
, orGetExecutionHistory
API call.aws stepfunctions get-execution-history \ --endpoint http://localhost:8083 \ --execution-arn arn:aws:states:us-east-1:123456789012:execution:LambdaSQSIntegration:executionWithHappyPathMockedServices
The following example demonstrates parts of a response to calling
GetExecutionHistory
using the execution ARN from the example response shown in step 2. In this example, the output ofLambdaState
andSQSState
is the mock data defined inMockedLambdaSuccess
andMockedSQSSuccess
in the mock configuration file. In addition, the mocked data is used the same way that data returned by performing actual service integration calls would be used. Also, in this example, the output fromLambdaState
is passed ontoSQSState
as input.{ "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 } } }, ... ] }
Configuration file for mocked service integrations in Step Functions
Step Functions Local is unsupported
Step Functions Local does not provide feature parity and is unsupported.
You might consider third party solutions that emulate Step Functions for testing purposes.
To use mocked service integrations, you must first create a mock configuration file named MockConfigFile.json
containing your mock configurations. Then provide Step Functions Local with the mock configuration file. This configuration file defines test cases, which contain mock states that use mocked service integration responses. The following section contains information about the structure of mock configuration that includes the mock states and mocked responses:
Mock configuration file structure
A mock configuration is a JSON object containing the following top-level fields:
-
StateMachines
- The fields of this object represent state machines configured to use mocked service integrations. -
MockedResponse
- The fields of this object represent mocked responses for service integration calls.
The following is an example of a mock configuration
file which includes a StateMachine
definition and 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!"
}
}
}
}
}
}
Mock configuration field reference
The following sections explain the top-level object fields that you must define in your mock configuration.
StateMachines
The StateMachines
object defines which state machines will use mocked service integrations. The configuration for each state machine is represented as a top-level field of StateMachines
. The field name is the name of the state machine and value is an object containing a single field named TestCases
, whose fields represent test cases of that state machine.
The following syntax shows a state machine with two test cases:
"MyStateMachine": {
"TestCases": {
"HappyPath": {
...
},
"SadPath": {
...
}
}
TestCases
The fields of TestCases
represent individual test cases for the state machine. The name of each test case must be unique per state machine and the value of each test case is an object specifying a mocked response to use for Task states in the state machine.
The following example of a TestCase
links two Task
states to two MockedResponses
:
"HappyPath": {
"SomeTaskState": "SomeMockedResponse",
"AnotherTaskState": "AnotherMockedResponse"
}
MockedResponses
MockedResponses
is an object containing multiple mocked response objects with unique field names. A mocked response object defines the successful result or error output for each invocation of a mocked Task state. You specify the invocation number using individual integer strings, such as “0”, “1”, “2”, and “3” or an inclusive range of integers, such as “0-1”, “2-3”.
When you mock a Task, you must specify a mocked response for every invocation. A response must contain a single field named Return
or Throw
whose value is the result or error output for the mocked Task invocation. If you do not specify a mocked response, the state machine execution will fail.
The following is an example of a MockedResponse
with Throw
and Return
objects. In this example, the first three times the state machine is run, the response specified in "0-2"
is returned, and the fourth time the state machine runs, the response specified in "3"
is returned.
"SomeMockedResponse": {
"0-2": {
"Throw": {
...
}
},
"3": {
"Return": {
...
}
}
}
Note
If you are using a Map
state, and want to ensure predictable responses for the Map
state, set the value of maxConcurrency
to 1. If you set a value greater than 1, Step Functions Local will run multiple iterations concurrently, which will cause the overall execution order of states across iterations to be unpredictable. This may further cause Step Functions Local to use different mocked responses for iteration states from one execution to the next.
Return
Return
is represented as a field of the MockedResponse
objects. It specifies the successful result of a mocked Task state.
The following is an example of a Return
object that contains a mocked response for calling Invoke
on a Lambda function:
"Return": {
"StatusCode": 200,
"Payload": {
"StatusCode": 200,
"body": "Hello from Lambda!"
}
}
Throw
Throw
is represented as a field of the MockedResponse
objects. It specifies the error output of
a failed Task. The value of Throw
must be an object containing an
Error
and Cause
fields with string values. In addition, the
string value you specify in Error
field in the MockConfigFile.json
must match the errors handled in the Retry
and Catch
sections of your state machine.
The following is an example of a Throw
object that contains a mocked response for calling Invoke
on a Lambda function:
"Throw": {
"Error": "Lambda.TimeoutException",
"Cause": "Lambda timed out."
}