Integration testing in serverless architectures can be challenging. Testing specific outcomes within managed services is cumbersome. sls-test-tools provides a range of utilities, setup, teardown and assertions to make it easier to write effective and high quality integration tests for Serverless Architectures on AWS.
I’m happy to announce that sls-test-tools now ships with new DynamoDB assertions!
Let's jump in a quick example 🏃♂️ !
1️⃣ Function to test
Let's consider a simple Lambda function that uploads client transaction data to DynamoDB.
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb";
type TransactionEvent = { clientName: string; transactionData: string };
const ddbDocClient = DynamoDBDocumentClient.from(new DynamoDBClient({}));
export const handler = async (event: TransactionEvent): Promise<string> => {
const { clientName, transactionData } = event;
await ddbDocClient.send(
new PutCommand({
TableName: "Sells",
Item: {
PK: clientName,
SK: new Date().toISOString(),
transactionData,
},
})
);
return "Transaction saved !";
};
As you can see, the function just makes a single "put" call to DynamoDB using the AWS SDK. In our integration test we want to make sure that the data has indeed been written to Dynamo.
2️⃣ Writing the test!
We will be using sls-test-tools new assertion toExistInDynamoTable
.
The integration testing can be done in 3 phases:
Triggering the initial event 🔥. In our scenario we call our lambda handler but we could also imagine sending an event in an Event Bus, uploading a file to S3...
Asserting the expected behavior ✅.
Cleaning what has been created 🧹. This step is very important in order to keep tests idempotent.
Following these three steps, the integration test implementation would be:
import { DocumentClient } from "aws-sdk/clients/dynamodb";
import MockDate from "mockdate";
import { AWSClient } from "sls-test-tools";
import { handler } from "./uploadTransactionDataToDynamo";
describe("Sells data upload integration testing", () => {
const documentClient: DocumentClient = new AWSClient.DocumentClient();
const mockDate = "2022-01-01T00:00:00.000Z";
MockDate.set(mockDate);
const event = { clientName: "John", transactionData: "someData" };
afterAll(async () => {
// 🧹 clean what you've created
await documentClient.delete({
TableName: "Sells",
Key: { PK: "John", SK: mockDate },
});
});
it("should upload transaction data to Dynamo", async () => {
// 🔥 trigger the initial event
await handler(event);
// ✅ assert the functional behavior you are testing
await expect({
PK: "John",
SK: mockDate,
}).toExistInDynamoTable("Sells");
});
All sls-test-tools assertions can of course be inverted using expect(..).not
.
You can use those assertions on all type of DynamoDB table, on a composite primary index table containing a partition key PK
and a sort key SK
like in the previous example, as well as in simpler table where primary index is only a partition key.
it("should upload transaction data to Dynamo", async () => {
await handler(event);
await expect({ PK: "John" }).toExistInDynamoTable("Sells");
await documentClient.delete({
TableName: "Sells",
Key: { PK: "John", SK: mockDate },
});
});
3️⃣ What's next !
Our team is working on typing sls-test-tools 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!
⭐️⭐️⭐️ Happy 2️⃣0️⃣2️⃣2️⃣ ⭐️⭐️⭐️
For more background about sls-test-tools, you can check out these two articles: Integration Testing Strategy for EventBridge and Bringing Simplicity to Serverless Integration Testing.
Top comments (0)