Testing Nest.js and MongoDB apps

A real-world example of how to simplify the development and testing process

Evgheni Calcutin
4 min readMay 25, 2020

Background

I’m a full-stack JavaScript developer. I love to make projects with cutting edge tools and frameworks such as MongoDB, Nest.js, Angular, Vue, React.

My family has a manufacturing business. In order to simplify their business process I started to develop an application. Here are some key goals:

  • to simplify warehouse assets management
  • to have clear vision overall company income and outcome
  • to calculate employees salary
  • to provide a dashboard with rich statistics

Each development stage should be tested carefully since even the smallest mistake might lead to dramatic results.

Some facts about the app:

  • 🏭 Multiple stocks management
  • 🧱 Over 26000 types of product
  • 🚀 Over 400 transactions daily

Since I develop both front-end and back-end apps, I found it quite boring and unproductive to test some features I just made. Once I add the controller, I must ensure it works properly. For that I used Swagger, Postman or simply calling endpoint from the web app.

That can become even worse if you need to test back-end service and verify that all queries are calculated properly.

When it comes to testing with Node.js and JavaScript — expect it to be intimidating. In this article, I will offer tips and techniques I have been used over the years for testing and maintaining small-to-large applications.

You will learn how to write integration and end-to-end tests easily for your Node.js and MongoDB application with mongodb-memory-database that runs on real instances of the database all without needing to set up an elaborate environment or complicated setup/tear-down code.

👉 Why unit tests are not enough?

While many developers focus on 100% coverage with unit tests, it is important that the code you write is not just tested in isolation. Integration and end-to-end tests give you that extra confidence by testing parts of your application together. These parts may be working just fine on their own, but in a large system, units of code rarely work separately.

Node.js and MongoDB together form one of the most popular duos of recent times. If you happen to be one of the many people using them, you are in luck.

Tools used

Situation

It’s all about managing warehouse assets.

Let’s say you need to move a couple of products from one stock to another. Overall it does not look over complicated. Everything you need is to decrease each product quantity from source stock and to increase in destination stock. But that will not be easy as soon as you need more details for example you want to know what products and how many of them have been moved between some date.

How it was

I have spent pretty much time manually exploring database changes and calculating values to verify everything works as expected and that became terrible. One moment I thought something I do wrong. Definitely!

Finally, I got a nice idea — tests. If I can write code, then I can automate some of the routines 😄.

Usage in Jest

In the Nest.js application, controllers are subjects for E2E tests and services(providers) for unit or integration tests.

To solve that easy way I made the transaction schema described below:

Now let’s take look on service it was never so easy😄 :

To calculate residue I was using the MongoDB aggregation framework. Those transactions with type INCOME are being accumulated with (+) sign, and OUTCOME with (-) sign.

Of course, calculating it manually is a terrible time-consuming task. This is how it can be automated and tested:

Notice the setup and tear-down actions in beforeEach and afterEach respectively. Each assertion will get an instance of a crystal clear database so each case is isolated but tested against a real database.

Now whenever you need to refactor something, you might be sure your application will work and provide the same results.

It’s obviously that setup and tear-down for each test case is not the best solution🤷‍♂️, however, it’s up to you to decide how you will use an in-memory database.

More complicated

Let’s imagine that product can be either as raw material like models FL-.*, NL-.*, WD-.*, or can represent tree-like dependence tree CF-203 of raw materials. Prices and values are approximate for this example:

That means, whenever our employee makes 5 coffins of CF-203 type, our accountant makes single waybill action of type PRODUCTION. Stock data should be updated as well as employee’s stats. Under the hood it calls multiple services to evaluate and update the database:

  • Increase product CF-203 quantity by 5
  • Decrease each raw material accordingly
  • Update employee’s stats

Now take into consideration a single waybill might have multiple products. I bet you will not enjoy testing that manually🙂.

Conclusion

Make sure that for an application that scales testing is a must-have. However, I start being confident that everything is working and there are no mistakes only by writing and running integration tests.

Full code is available on git: https://github.com/veles-md/erp-backend

Other alternatives you might take look and start using: https://www.npmjs.com/package/mongo-unit

I will be very grateful if you contact me for any typo I made or a suggestion proposal.

Telegram: https://t.me/calcutin

--

--