# How to Write Integration Tests for MongoDB Atlas Functions

> 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.

>Prefer to learn by video? Many of the concepts I cover in this series are available in this video.

## Integration Testing MongoDB Atlas Functions

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.

### Example Integration Test

Let's take a look at how I tested the integration between the `storeCsvInDb` Atlas Function, the `removeBreakingCharacters` Atlas 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 `removeBreakingCharacters` function 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 `removeBreakingCharacters` function and the database.

We won't use any mocks in the integration tests. Instead, we'll let the `storeCsvInDb` function call the `removeBreakingCharacters` function and the database.

The first thing I did was import `MongoClient` from the `mongodb` module. We will use MongoClient later to connect to the MongoDB database hosted on Atlas.

``` javascript
const { MongoClient } = require('mongodb');
```

Next, I imported several constants from `constants.js`. I created the `constants.js` file to store constants I found myself using in several test files.

``` javascript
const { TwitterStatsDb, statsCollection, header, validTweetCsv, validTweetJson, validTweetId, validTweetUpdatedCsv, validTweetUpdatedJson, emojiTweetId, emojiTweetCsv, emojiTweetJson, validTweetKenId, validTweetKenCsv, validTweetKenJson } = require('../constants.js');
```

Next, I imported the `realm-web` SDK. I'll be able to use this module to call the Atlas Functions.

``` javascript
const RealmWeb = require('realm-web');
```

Then I created some variables that I'll set later.

``` javascript
let collection;
let mongoClient;
let app;
```

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.)

``` javascript
beforeAll(async () => {
   // Connect to the App Services app
   app = new RealmWeb.App({ id: `${process.env.REALM_APP_ID}` });

   // Login to the app with anonymous credentials
   await app.logIn(RealmWeb.Credentials.anonymous());

   // Connect directly to the database
   const uri = `mongodb+srv://${process.env.DB_USERNAME}:${process.env.DB_PASSWORD}@${process.env.CLUSTER_URI}/test?retryWrites=true&w=majority`;
   mongoClient = new MongoClient(uri);
   await mongoClient.connect();
   collection = mongoClient.db(TwitterStatsDb).collection(statsCollection);
});
```

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.

``` javascript
afterAll(async () => {
   await mongoClient.close();
})
```

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.

``` javascript
beforeEach(async () => {
   await collection.deleteMany({});
});
```

Now that my test infrastructure was complete, I was ready to start writing a test case that focuses on storing a single valid Tweet.

``` javascript
test('Single tweet', async () => {

   expect(await app.functions.storeCsvInDb(header + "\n" + validTweetCsv)).toStrictEqual({
      newTweets: validTweetId],
      tweetsNotInsertedOrUpdated: [],
      updatedTweets: []
   });

   const tweet = await collection.findOne({ _id: validTweetId });
   expect(tweet).toStrictEqual(validTweetJson);
});
```

The test begins by calling the `storeCsvInDb` Atlas 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.

## Wrapping Up

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: . 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.

## Related Links

Check out the following resources for more information:

-   GitHub Repository: Social Stats
-   Video: DevOps + MongoDB Atlas Functions = 😍
-   Documentation: MongoDB Atlas Functions
-   MongoDB Atlas
-   MongoDB Charts