How to Write Integration Tests for MongoDB Atlas Functions
Lauren SchaeferPublished Jan 17, 2022 • Updated Aug 26, 2022
Rate this tutorial
As of June 2022, the functionality previously known as MongoDB Realm is now named Atlas App Services. Atlas App Services refers to the cloud services that simplify building applications with Atlas – Atlas Data API, Atlas GraphQL API, Atlas Triggers, and Atlas Device Sync. Realm will continue to be used to refer to the client-side database and SDKs. Some of the naming or references in this article may be outdated.
Integration tests are vital for apps built with a serverless architecture. Unfortunately, figuring out how to build integration tests for serverless apps can be challenging.
Today, I'll walk you through how to write integration tests for apps built with MongoDB Atlas Functions.
This is the second post in the DevOps + MongoDB Atlas Functions = 😍 blog series. Throughout this series, I'm explaining how I built automated tests and a CI/CD pipeline for the Social Stats app. In the first post, I explained what the Social Stats app does and how I architected it. Then I walked through how I wrote unit tests for the app's serverless functions. If you haven't read the first post, I recommend starting there to understand what is being tested and then returning to this post.
Today we'll focus on the middle layer of the testing pyramid: integration tests.
Integration tests are designed to test the integration of two or more components that work together as part of the application. A component could be a piece of the code base. A component could also exist outside of the code base. For example, an integration test could check that a function correctly saves information in a database. An integration test could also test that a function is correctly interacting with an external API.
When following the traditional test pyramid, a developer will write significantly more unit tests than integration tests. When testing a serverless app, developers tend to write nearly as many (or sometimes more!) integration tests as unit tests. Why?
Serverless apps rely on integrations. Serverless functions tend to be small pieces of code that interact with other services. Testing these interactions is vital to ensure the application is functioning as expected.
Let's take a look at how I tested the integration between the
storeCsvInDbAtlas Function, the
removeBreakingCharactersAtlas Function, and the MongoDB database hosted on Atlas. (I discuss what these functions do and how they interact with each other and the database in my previous post.)
I decided to build my integration tests using Jest since I was already using Jest for my unit tests. You can use whatever testing framework you prefer; the principles described below will still apply.
Let's focus on one test case: storing the statistics about a single Tweet.
As we discussed in the previous post, the storeCsvInDb function completes the following:
- Calls the
removeBreakingCharactersfunction to remove breaking characters like emoji.
- Converts the Tweets in the CSV to JSON documents.
- Loops through the JSON documents to clean and store each one in the database.
- Returns an object that contains a list of Tweets that were inserted, updated, or unable to be inserted or updated.
When I wrote unit tests for this function, I created mocks to simulate the
removeBreakingCharactersfunction and the database.
We won't use any mocks in the integration tests. Instead, we'll let the
storeCsvInDbfunction call the
removeBreakingCharactersfunction and the database.
The first thing I did was import
mongodbmodule. We will use MongoClient later to connect to the MongoDB database hosted on Atlas.
Next, I imported several constants from
constants.js. I created the
constants.jsfile to store constants I found myself using in several test files.
Next, I imported the
realm-webSDK. I'll be able to use this module to call the Atlas Functions.
Then I created some variables that I'll set later.
Now that I had all of my prep work completed, I was ready to start setting up my test structure. I began by implementing the beforeAll() function. Jest runs
beforeAll()once before any of the tests in the file are run. Inside of
beforeAll()I connected to a copy of the App Services app I'm using for testing. I also connected to the test database hosted on Atlas that is associated with that App Services app. Note that this database is NOT my production database. (We'll explore how I created Atlas App Services apps for development, staging, and production later in this series.)
I chose to use the same app with the same database for all of my tests. As a result, these tests cannot be run in parallel as they could interfere with each other.
My app is architected in a way that it cannot be spun up completely using APIs and command line interfaces. Manual intervention is required to get the app configured correctly. If your app is architected in a way that you can completely generate your app using APIs and/or command line interfaces, you could choose to spin up a copy of your app with a new database for every test case or test file. This would allow you to run your test cases or test files in parallel.
I wanted to ensure I always closed the connection to my database, so I added a call to do so in the afterAll() function.
I also wanted to ensure each test started with clean data since all of my tests are using the same database. In the beforeEach() function, I added a call to delete all documents from the collection the tests will be using.
Now that my test infrastructure was complete, I was ready to start writing a test case that focuses on storing a single valid Tweet.
The test begins by calling the
storeCsvInDbAtlas Function just as application code would. The test simulates the contents of a Twitter statistics CSV file by concatenating a valid header, a new line character, and the statistics for a Tweet with standard characters.
The test then asserts that the function returns an object that indicates the Tweet statistics were successfully saved.
Finally, the test checks the database directly to ensure the Tweet statistics were stored correctly.
After I finished this integration test, I wrote similar tests for Tweets that contain emoji as well as for updating statistics for Tweets already stored in the database.
You can find the complete set of integration tests in storeCsvInDB.test.js.
Integration tests are especially important for apps built with a serverless architecture. The tests ensure that the various components that make up the app are working together as expected.
The Social Stats application source code and associated test files are available in a GitHub repo: https://github.com/mongodb-developer/SocialStats. The repo's readme has detailed instructions on how to execute the test files.
Be on the lookout for the next post in this series where I'll walk you through how to write end-to-end tests (sometimes referred to as UI tests) for serverless apps.
Check out the following resources for more information:
Continuously Building and Hosting our Swift DocC Documentation using Github Actions and Netlify
May 10, 2022