I would like to introduce a new helper tool I’ve developed for integration tests – SnsTestReceiver. This my new little pet helps to test SNS allowing the assertion of the notifications published in an easy and scalable way.
TL; DR;
SnsTestReceiver is a simple RESTful API that receives notifications from SNS and stores them in memory for quick access. The setup instructions, source code, and an example can be found on my GitHub here.
AWS SNS
As you’ve probably already know, AWS SNS provides an interface to publish notifications to one (forward) or more (fan out) subscriptions that could be using different protocols. SNS provides many more nice features – check the Getting started documentation on AWS.
Integration tests challenge
There might be different definitions of an integration test, however I test application’s integration with the dependencies, and whenever possible using some realistic mocks. And if you are developing against AWS services locally or run integration tests in isolation, the Localstack is a must have tool :) I wrote about the Localstack setup for local development a while ago.
Each application, e.g. Lambda, has it’s own integration tests project. Inside the project there are multiple classes with the integration tests, and a common pattern is to invoke Lambda’s handler with an event, and assert that the expected action has been completed, e.g. SNS notification has been published. And you may have just a single Lambda in your solution, or even multiple Lambdas.
Now to keep the testing simple, we could go with a few different options:
- Unit test — i.e. don’t write any integration tests at all. An easy option which provides less confidence in the code option.
- Use a dummy SQS queue — at first glance, this may look like the best option. You could stick to Localstack and just install the SQS SDK. While there are several SQS features that makes it highly scalable, however they are also quite inconvenient to use in the integration tests. Especially, if you have multiple integration test projects within the same solution that publish to the same SNS topic. See the diagram and the notes below.
SnsTestReceiver in a nutshell
If you’ve read so far, you must be intrigued about the solution I am proposing :) While it’s neither ground breaking nor super innovative, however it simplifies SNS testing, improves tests performances and scalability. See the revised diagram below.
Feature highlights:
- Docker image is ready to use
- RESTful API — get by message ID, or search for a matching string in the body
- In memory storage for fast data access, and easy cleanup
- SDK for .NET Core available as a NuGet package
- There is no message wait time or visibility timeout
- As long as you use unique IDs inside the message body, you can run all the integration tests in parallel
Setup SnsTestReceiver
The setup requires 3 simple steps.
1. Pull the docker image
Add the following into your docker-compose.yml
file to pull the docker image, and expose port 5000:
sns-test-receiver:
image: ignassakalauskas/sns-test-receiver:latest
container_name: sns-test-receiver
ports:
- "5000:5000"
2. Setup SNS subscription
Assuming you have created arn:aws:sns:eu-west-1:000000000000:notifications
SNS topic already, and have awslocal installed, simply create an HTTP subscription to the SnsTestReceiver’s /messages
endpoint.
awslocal sns subscribe --topic-arn "arn:aws:sns:eu-west-1:000000000000:notifications" --protocol http --notification-endpoint http://sns-test-receiver:5000/messages
3. Assert the notification
In the assertion part of your integration tests, find the published notification by let’s say it’s ID.
// ...
// When
await sns.PublishAsync(request);
// Then
var result = await testReceiver.SearchAsync(expectedId);
result.Should().HaveCount(1);
result.Single().Subject.Should().Be(request.Subject);
// ...
The full example code is available on GitHub.
Conclusions
While for a simple integration test it might suffice to use a dummy SQS queue and the SQS SDK, however once you start scaling, i.e. having more and more tests, and more and more assemblies that run in parallel, you need a more robust solution.
SnsTestReceiver addresses the dummy SQS queue shortcomings and provides an easy setup via docker image + SDK for .NET Core NuGet package.
The source code could be found on my GitHub.