Skip to content

Latest commit

 

History

History

step-functions-local

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 

typescript: 4.5.5 AWS:Step Functions test: unit

Typescript: AWS Step Functions Local Testing using Jest Example

Introduction

Step Functions Local testing with mock configuration provides the capability to mock AWS service integrations that are present in a state machine. This helps in testing the state machine in isolation.

This is a sample project which showcases how to run Step Functions local tests with mocks using Jest instead of running ad-hoc CLI commands. Testcontainers is used to run the Step Functions Local Docker image.

This is not a replacement of the strategy shown in the blog above but another way to test Step Functions state machine with better assertion capabilities. Teams currently using Javascript / Typescript for Serverless development can leverage this strategy in their current applications.


Contents


About this Pattern

System Under Test (SUT)

The SUT is a sales lead generation sample workflow implemented with AWS Step Functions. In this example, new sales leads are created in a customer relationship management system. This triggers the sample workflow execution using input data, which provides information about the contact.

Using the sales lead data, the workflow first validates the contact’s identity and address. If valid, it uses Step Functions’ AWS SDK integration for Amazon Comprehend to call the DetectSentiment API. It uses the sales lead’s comments as input for sentiment analysis.

If the comments have a positive sentiment, it adds the sales leads information to a DynamoDB table for follow-up. The event is published to Amazon EventBridge to notify subscribers.

If the sales lead data is invalid or a negative sentiment is detected, it publishes events to EventBridge for notification. No record is added to the Amazon DynamoDB table. The following Step Functions Workflow Studio diagram shows the control logic:

System Under Test (SUT)

Goal

The goal of this example is to test AWS Step Functions state machines in isolation using mocked responses for the external services which need to conform to actual responses before testing. With mocking, developers get more control over the type of scenarios that a state machine can handle, leading to assertion of multiple behaviors. Testing a state machine with mocks can also be part of the software release. Asserting on behaviors like error handling, branching, parallel, dynamic parallel (map state) helps test the entire state machine’s behavior. For any new behavior in the state machine, such as a new type of exception from a state, you can mock and add as a test.

Description

In this example, you test a scenario in which:

  1. The identity and address are successfully validated using a Lambda function.
  2. A positive sentiment is detected using the Comprehend.DetectSentiment API after three retries.
  3. A contact item is written to a DynamoDB table successfully
  4. An event is published to an EventBridge event bus successfully

The execution path for this test scenario is shown in the following diagram (the red and green numbers have been added). 0 represents the first execution; 1, 2, and 3 represent the max retry attempts (MaxAttempts), in case of an InternalServerException.

System Under Test Description (SUT)

Top


About this Example

To use service integration mocking, create a mock configuration file with sections specifying mock AWS service responses. These are grouped into test cases that can be activated when executing state machines locally. The following example provides code snippets and the full mock configuration is available in the code repository.

To mock a successful Lambda function invocation, define a mock response that conforms to the Lambda.Invoke API response elements. Associate it to the first request attempt:

"CheckIdentityLambdaMockedSuccess": {
  "0": {
    "Return": {
      "StatusCode": 200,
      "Payload": {
        "statusCode": 200,
        "body": "{\"approved\":true,\"message\":\"identity validation passed\"}"
      }
    }
  }
}

To mock the DetectSentiment retry behavior, define failure and successful mock responses that conform to the Comprehend.DetectSentiment API call. Associate the failure mocks to three request attempts, and associate the successful mock to the fourth attempt:

"DetectSentimentRetryOnErrorWithSuccess": {
  "0-2": {
    "Throw": {
      "Error": "InternalServerException",
      "Cause": "Server Exception while calling DetectSentiment API in Comprehend Service"
    }
  },
  "3": {
    "Return": {
      "Sentiment": "POSITIVE",
      "SentimentScore": {
        "Mixed": 0.00012647535,
        "Negative": 0.00008031699,
        "Neutral": 0.0051454515,
        "Positive": 0.9946478
      }
    }
  }
}

Note that Step Functions Local does not validate the structure of the mocked responses. Ensure that your mocked responses conform to actual responses before testing. To review the structure of service responses, either perform the actual service calls using Step Functions or view the documentation for those services.

Next, associate the mocked responses to a test case identifier:

"RetryOnServiceExceptionTest": {
  "Check Identity": "CheckIdentityLambdaMockedSuccess",
  "Check Address": "CheckAddressLambdaMockedSuccess",
  "DetectSentiment": "DetectSentimentRetryOnErrorWithSuccess",
  "Add to FollowUp": "AddToFollowUpSuccess",
  "CustomerAddedToFollowup": "CustomerAddedToFollowupSuccess"
}

With the test case and mock responses configured, you can use them for testing with Step Functions Local.

Key Files in the Project

Top


Unit Test

Prerequisites

Unit Test description

This example contains a sample event with new user registration data to be processed by the state machine. The unit tests will check how the state machine behaves for each of the following scenarios defined in the MockConfigFile.json file:

  • HappyPathTest: every external service runs succesfully and the state machine exits with "CustomerAddedToFollowup".
  • NegativeSentimentTest: the contact details are properly formatted, a negative sentiment is detected within the user comments and the state machine exits with "NegativeSentimentDetected".
  • RetryOnServiceExceptionTest: the sentiment detection service fails three times and the state machine retries until successfully retrieving the sentiment in the fourth attempt.

Run the Unit Test

Make sure docker engine is running before running the tests.

step-functions-local$ docker version
Client: Docker Engine - Community
Cloud integration: v1.0.29
Version:           20.10.21
API version:       1.41
...

To run the unit tests:

step-functions-local$ cd src
src $ npm install
src $ npm run test

Top