LocalStack as a Drop-in Replacement for Step Functions Local
Learn how to use LocalStack as a drop-in replacement for AWS Step Functions Local to test your state machine workflows locally with mocking capabilities, allowing you to avoid undesirable side effects, speed up test execution, and validate workflow logic without deploying to the cloud.

Introduction
AWS Step Functions provides resilient orchestration of AWS services and is very popular in the serverless community. While Step Functions can be simply regarded as a visual programming language, it provides durable execution in distributed systems, with built-in support for retries and crash recovery. You can construct workflows using the Amazon States Language, written directly in JSON or YAML formats, or by using the Workflow Studio graphical editor.
If you’re an AWS Step Functions user, you can now use LocalStack to mock service integrations, in the same way you can with Step Functions Local. If you believe in unit testing (and you should!), you’ll know that mocking parts of your code is important. You can focus your tests on the Step Functions workflow, while skipping over less-interesting parts of your application. You can avoid undesirable side effects in your test cases (such as writing to a database or sending an email), and generally make your tests run faster.
In this tutorial, you’ll run an example application from the AWS Step Functions site. LocalStack is a drop-in replacement for the AWS Cloud, so we can easily reuse examples from AWS. You’ll then learn how to test the Step Functions workflow using LocalStack’s new mocking feature.
Key Concepts
To aid with local development and testing of Step Functions workflows, AWS provides the Step Functions Local emulator. Similar to LocalStack, this tool runs inside a Docker container on your local machine, or inside a CI environment. You must specify the --endpoint-url
flag (or similar) to point your client-side tools to the Step Functions emulator, rather than connecting to the AWS cloud.
A unique feature of Step Functions Local is the ability to mock service integrations when a state machine is executed. That is, during a workflow execution, you can provide a set of mock responses to be used in place of invoking a Lambda function, or calling an AWS service.
This mocking feature isn’t available in the AWS cloud, making local emulation a valuable tool when testing workflows. However, as of 2024, AWS no longer supports their Step Functions Local emulator, and recommends customers use third-party emulators.
At LocalStack, we fully emulate this mocking approach, allowing use of the latest Step Functions features (such as JSONata, Variables, and Distributed Map) with only minor updates to your existing test suite.
Mock Configuration File
To write test cases for your Step Functions workflow, you’ll use the same syntax as Step Functions Local. This allows you to reuse your existing test suite with LocalStack without modification.
The mock configuration file is a JSON document with two main sections:
TestCases
: This section provides a list of test cases, with each containing a map of Step Functions state names to the corresponding mock response name.MockedResponses
: This section contains the actual mocked data. Each entry is a named response that provides the specific output to be returned when a state is mocked.
Enabling Mocking
To make the mock configuration file accessible to the LocalStack emulator, you need to mount the file into the LocalStack Docker container and set an environment variable pointing to it.
LOCALSTACK_SFN_MOCK_CONFIG=/tmp/MockConfigFile.json \ localstack start --volume ./MockConfigFile.json:/tmp/MockConfigFile.json
Targeting Test Cases
To execute a Step Functions workflow with a specific mock test case, you append the test case name to the end of the state machine ARN, separated by a #
.
awslocal stepfunctions start-execution \ --state-machine arn:aws:states:us-east-1:000000000000:stateMachine:TestStateMachine#BuyStockTestCase
Prerequisites
localstack
CLI withLOCALSTACK_AUTH_TOKEN
configured- Docker
- AWS CLI with the
awslocal
wrapper - SAM CLI with the
samlocal
wrapper - AWS account with access to Step Functions
Step 1: Setup the example application
We’ll use a standard example from the AWS documentation that orchestrates the durable execution of a stock sale or purchase process.
In this tutorial, you’ll use Step Functions mocking to test both the Buy path and the Sell path. You’ll mock the Check Stock Price
state to return a hard-coded stock price (high or low, depending on the test case) and mock the Buy Stock
and Sell Stock
states to avoid their side effects.
This results in two test cases:
BuyStockTestCase
- Mocks the stock price to be low (27), and validates that theBuy Stock
state is reached.SellStockTestCase
- Mocks the stock price to be high (70), and validates that theSell Stock
state is reached.
1.1: Copy the template from AWS documentation
Start by copying the example provided in the AWS documentation. This example uses a CloudFormation template to create a new Step Functions state machine and associated Lambda functions. Instead of creating the state machine in the AWS Cloud, you should copy the CloudFormation template and save it to a local file.
Follow these steps:
- Go to the AWS Step Functions console (the AWS console, not the LocalStack console), and select Create State Machine, then choose Create from template, then press Next.
- Locate the template named Orchestrate Lambda functions, then press Next.
- Select Run a demo (if not already selected) and press Use template, followed by Deploy and run.
- Navigate to the AWS CloudFormation service console and locate the stack you just created. It will be named
something like
StepFunctionsSample-HelloLambda
(with random characters appended). - Switch to the Template tab and select Copy to copy the CloudFormation template to your clipboard.
- Paste the template into a local file in your development environment. Name it
template.yml
.
Note that AWS may change its Console UI from time to time, so the exact steps may differ when you try this.
To clean up your cloud-based AWS resources, press Delete on the AWS CloudFormation stack. This ensures you won’t accidentally trigger charges in the AWS cloud.
1.2: Provide a hard-coded State Machine name
A fundamental weakness in how Step Functions mocking configuration works is that it requires a hard-coded state machine name. Resources without a hard-coded name are given an auto-generated one, making it impossible to know the exact name before deployment. LocalStack, aiming to be a drop-in replacement, follows this same behaviour.
As a workaround for the stock-trading example, edit template.yml
to add the StateMachineName
field for the StockTradingStateMachine
resource. At the time of writing, this involves adding line 338, as follows:
StockTradingStateMachine: Type: 'AWS::StepFunctions::StateMachine' Properties: StateMachineName: TestStateMachine <<<<<----- Add this line DefinitionSubstitutions: RequestHumanApprovalSqsUrl: !Ref RequestHumanApprovalSqs ReportResultSnsTopicArn: !Ref ReportResultSnsTopic
Step 2: Construct the MockConfigFile.json
file
For our two test cases, you’ll apply mocked values. For BuyStockTestCase
:
- Mock the
Check Stock Price
state to return the value 27 (a low price) - Mock the
Request Human Approval
state to automatically approve the stock purchase. - Mock the
Buy Stock
state to avoid calling the Lambda function that makes the purchase.
For SellStockTestCase
:
- Mock the
Check Stock Price
state to return the value 70 (a high price) - Mock the
Request Human Approval
state to automatically approve the stock sale. - Mock the
Sell Stock
state to avoid calling the Lambda function.
The resulting MockConfigFile.json
is as follows. Create this file in your project directory:
{ "StateMachines": { "TestStateMachine": { "TestCases": { "BuyStockTestCase": { "Check Stock Price": "MockedLowStockPrice", "Request Human Approval": "SkipApproval", "Buy Stock": "SkipBuyOrSellStock" }, "SellStockTestCase": { "Check Stock Price": "MockedHighStockPrice", "Request Human Approval": "SkipApproval", "Sell Stock": "SkipBuyOrSellStock" } } } }, "MockedResponses": { "MockedLowStockPrice": { "0": { "Return": { "StatusCode": 200, "Payload": { "stock_price": 27 } } } }, "MockedHighStockPrice": { "0": { "Return": { "StatusCode": 200, "Payload": { "stock_price": 70 } } } }, "SkipApproval": { "0": { "Return": "approved" } }, "SkipBuyOrSellStock": { "0": { "Return": { } } } }}
For more details on the syntax, review the AWS documentation.
Step 3: Run the Test Cases
As the final step, make the MockConfigFile.json
file accessible to the LocalStack emulator. Assuming you have the file in your current working directory, start the emulator with:
LOCALSTACK_SFN_MOCK_CONFIG=/tmp/MockConfigFile.json \ localstack start --volume ./MockConfigFile.json:/tmp/MockConfigFile.json
In another shell window, deploy the application with:
samlocal deploy --stack-name step-functions-mocking
To execute the Step Functions workflow with mocking enabled for the BuyStockTestCase
, append the test case name to the end of the state machine ARN.
For example, to execute the BuyStockTestCase
, use:
awslocal stepfunctions start-execution \ --state-machine arn:aws:states:us-east-1:000000000000:stateMachine:TestStateMachine#BuyStockTestCase
To run the SellStockTestCase
, change the test case name in the ARN:
awslocal stepfunctions start-execution \ --state-machine arn:aws:states:us-east-1:000000000000:stateMachine:TestStateMachine#SellStockTestCase
Step 4: Manually verify success
In a real test framework, you’ll also want to assert (using your favourite test library) that the correct Step Functions states are reached, but that’s out of scope for an article focused on mocking. What’s important for now is controlling the response for each task in the workflow, and skipping the states that have undesirable side effects.
For now, you should do some visual checks that the mocking worked:
- Check the LocalStack Step Functions console to check for the correct responses in the workflow execution history.
- Check the LocalStack Lambda console to ensure the Lambda functions did not execute, but were instead mocked out.
If both of these manual steps are successful, then congratulations! You’ve successfully run a test case with mocking.
Conclusion
In this tutorial, you’ve learned how to create an AWS Step Functions mocking file to specify which parts of the workflow should be skipped, and which pre-defined values should be returned instead. Mocking is an important part of writing test cases, allowing you to avoid undesirable side effects, to speed up your test cases, and to trigger edge case behaviour.
LocalStack’s Step Functions service now supports the same mocking feature as Step Functions Local. This allows the use of test mocking, in conjunction with the latest Step Functions features (such as JSONata, Variables, and Distributed Map). The mocking configuration file has the same syntax as Step Functions Local, so the effort to migrate away from the (no longer supported) Step Functions Local emulator should be minimal.