The Best Integration Testing Library for Serverless Projects Now Supports Typescript!
Stan Hannebelle
Posted on March 1, 2022
Local development is an anti-pattern in the serverless world. If you're not convinced yet, have a look at Gareth McCumskey's talk given at Serverless Days Paris. 🎤
Having a local replica of the AWS resources deployed in production is not recommended as local emulations will not behave exactly like the production stack.
In this context, building a relevant integration testing strategy becomes painful as integration tests in a local environment do not guarantee a correct behavior in production.
Therefore, when it comes to integration tests, as a serverless developer you should:
- Avoid mocking serverless services and testing your application in a local environment ❌
- Use real underlying serverless services as much as possible to test your application ✅
How can you achieve that? 🤔
Using sls-test-tools 🏅
sls-test-tools provides custom Jest assertions to easily implement effective and high-quality integration tests for serverless architectures on AWS.
1️⃣ sls-test-tools was not typed 😭 but it now supports TypeScript 😍 !
sls-test-tools is a JS project and doesn’t provide types for TS developers. 🤯
However, at Kumo, our standard in terms of programming language for serverless projects is TypeScript.
Not having a tool to properly test our serverless TS projects has been an important issue for us in terms of developer experience and stability of our delivered applications.
So I migrated sls-test-tools from JS to TS; enabling the whole serverless/TS community to leverage sls-test-tools.
💡 I typed it using ts-migrate
ts-migrate is a tool I strongly recommend. It's been developed by Airbnb to help to migrate easily JavaScript projects to TypeScript.
The typed version of sls-test-tools has now been released (version 1.0.7 ) so:
- ⭐⭐⭐ sls-test-tools can be used in TS projects ⭐⭐⭐
- sls-test-tools API didn’t change for JS projects 🤝
2️⃣ New to sls-test-tools? Here is a quick tutorial
Use case
As an example, let’s consider a lambda function that publishes an event containing client contact details on EventBridge.
export const handler = async (): Promise<string> => {
const eventPayload = {
id: 'clientId',
email: 'client@mail.com',
};
await customerCreatedEvent.publish(eventPayload);
return eventPayload.id;
};
Step 1
This lambda function firstly sets an Event payload.
const eventPayload = {
id: 'clientId',
email: 'client@mail.com',
};
This block could typically be replaced by data retrieved from any appropriate database service and some business logic.
Step 2
The lambda function publishes the event to an EventBridge bus.
await customerCreatedEvent.publish(eventPayload);
Let’s test this!
To be sure that this lambda correctly publishes an event to the EventBridge bus, let’s write an integration test thanks to sls-test-tools.
import { AWSClient, EventBridge } from 'sls-test-tools';
const lambda = new AWSClient.Lambda();
describe('Event Bridge Integration Testing ', () => {
it('correctly publishes an event to the event bus when the lambda is invoked', async () => {
// Step 1: Arrange
const eventBridge = await EventBridge.build(busName);
// Step 2: Act
await lambda.invoke({ FunctionName: lambdaName }).promise();
// Step 3: Assert
const eventBridgeEvents = await eventBridge.getEvents();
expect(eventBridgeEvents).toHaveEvent();
expect(eventBridgeEvents).toHaveEventWithSource('client');
// Step 4: Clean
await eventBridge.destroy();
});
});
Step 1: Arrange - Update the real stack to run tests
const eventBridge = await EventBridge.build(busName);
Firstly, the build function provided by sls-test-tools is called. It checks that your stack includes an EventBridge bus with a given name. It also deploys an SQS queue used as a destination for all events sent in the bus. This queue is used to watch specific events for your Jest test asserts.
Step 2: Act - Execute the lambda
await lambda.invoke({ FunctionName: lambdaName }).promise();
Secondly, the lambda is executed.
Step 3: Assert - Expect real change on the stack
const eventBridgeEvents = await eventBridge.getEvents();
expect(eventBridgeEvents).toHaveEvent();
expect(eventBridgeEvents).toHaveEventWithSource('client');
Then, the getEvents function is called. It returns published messages present in the SQS queue which contain information about published events in EventBridge Bus.
These messages are used to run two assertions to check that during the execution of the lambda:
- An event has been published to the bus
- An event has been published to the bus with a source value of client
Step 4: Clean - Discard any modification to the stack made during the test
await eventBridge.destroy();
Finally, the SQS queue is destroyed in order to clean the tested stack.
3️⃣ Next steps
Our team, with the support of aleios and the community, is working on improving the DX of sls-test-tools (using environment variables instead of cli arguments...) and on adding more custom Jest assertions. We are also writing a more exhaustive article on Serverless integration testing, please feel free to subscribe so you can be notified when it will come out!
The community of sls-test-tools contributors is active and growing. Don’t hesitate to create an issue or open a PR if you want to get involved in the development of the project!
Posted on March 1, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
March 1, 2022