Image taken from Unsplash

Using Mocha for Test-Driven Development in building API with Node / Express

Bilguun Batbold
May 18, 2019 · 7 min read

Automated tests? Why? How?

For the longest time, I was just writing functionalities and manually testing them to ensure they work as expected. Every single new functionality, I would test my service manually ten times, hundred times, THOUSANDS times… you get it.

Some of my key problems with manual testing were:

I guarantee you that the extra effort put in writing tests will eventually pay off big time! So let’s get started!

What is TDD or BDD?

Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: first the developer writes an (initially failing) automated test case that defines a desired improvement or new function, then produces the minimum amount of code to pass that test, and finally refactors the new code to acceptable standards.

The following sequence of steps is generally followed:

So TDD ensures that we write logic that is actually tested and is of high quality. BDD (Behavior-Driven Development) is based on TDD and promotes collaboration between product managers and developers.

Let’s say we have the following array:

var menu = [ 'green', 'chai', 'oolong' ];

In TDD, we will verify like so:

assert.isArray(menu)

In BDD, we will instead write it like:

expect(menu).to.be.an('array');

We can write more complex assertions but this is the gist of it. You can clearly see that BDD style is much more readable, even for non developers.

Prerequisites

Now that we have the basics of why its of great importance to write tests, let’s get down to actual implementation.

I assume that you have had previous knowledge of creating APIs in Express, but feel free to follow along even if you do not have prior experience. These are the required installations before we get started:

Tutorial

We will be creating a simple REST API that will handle CRUD operations on users.

Let’s create a new folder called nodejs-testing. Go to the folder and run the following:

npm init --yes
npm i express mocha chai supertest nyc mongoose

We will first initialize a new npm project with default parameters, and add the required libraries.

Let’s first create our bare minimum express app. Make sure your project structure looks like this:

Project structure

User.model.js

First we create a new schema to define a new user schema. For simplicity, we will only use 3 properties for the user.

App.js

Next we write some logic in our app.js. Here we are connecting to our MongoDB database, use our usersRouter (which is empty at the moment, it is fine) and create error on any end points that are not available. Finally we export the app. We export the app so that we can do tests with the app, without listening to any ports. The actual startup happens in bin/www

./bin/www

Here we just create a HTTP server and listen to incoming requests in production mode (or development).

Now that we have the super basic skeleton, let’s try running the app!

node bin/www
test server listening on port 3000
Connected to MongoDB at mongodb://localhost/tddDB...

Great! Our server is listening on port 3000! When we actually try to request any resource from localhost:3000, we get the following message {“message”:”Not Found”}. And that is alright, we will get to it in a minute.

Writing Tests

The reason why we left user.controller and user.route empty is because I wanted to demonstrate how you can use TDD approach to write your application logic. We will first write the tests, let it run and fail, and then add the logic to make it pass. Repeat until all our desired tests pass!

Before we start writing tests, we need to ensure that our tests have a proper setup and tear down in place. This is to ensure that each test begins from a fresh state, so that it can be predictable and reproducible. Learn more about Mocha Hooks here.

Let’s look through this basic integration test that tests our api/users end point. We use describe to group the tests together and add some structure to it. We then use it to write the individual tests.

First we have the main grouping, describe("api/users") Then, before each individual test, we will clear our Users collection in MongoDB. In our describe("GET /") block, we insert few users into the database, and expect some result. Note that we are using BDD style, by using Chai Expect. It is really easy to understand, for example, when we write expect(res.status).to.equal(200); we can immediately know that we expect the response status to be 200, and to also have a body array of length 2.

Running Tests

To run the test, we simply do the following:

mocha --timeout 10000 --exit

We increase the default timeout parameter to 10 seconds, just to ensure that our database operations have sufficient time to execute.

Test output

You will then receive a similar output as shown above. Out describe and it statements are properly shown and we can see where the tests pass and fail with proper structure.

Adding logic to pass the tests

Now that we have written our expected results via the tests, let’s add the logic to pass them.

User.controller.js

User.route.js

Add the codes to the controller and the routes as shown above. In our controller, we have 2 methods. One gets all users, and one gets a specific user. We also check if the object id passed is valid or not, and send that responses accordingly to how we have defined our tests to behave.

Run the test again and the output should show:

Great! We have done our first round of TDD! Next we can add more tests to handle POST, PUT and DELETE. I will just add some simple logic but please feel free to expand on them accordingly.

I have added few tests here to ensure that our CRUD operations are working. Note that this is not the complete set, more tests have to be written to ensure code stability, but it can be a starting point for you.

Controller has been updated with few more methods
Router has been updated to support more CRUD operations

Let’s run the test again!

Our output with 8 tests

Nice! We have done few more rounds of TDD and ensured that our code works for sure, and we can sleep better at night knowing that it works as per intended.

Showing code coverage

Now it’s time to actually see how well we cover the code! Let’s use the nyc module we have installed earlier.

Add the test and coverage scripts

What it does is that it will generate both text and HTML reports, which gives you a more visual status of your code coverage!

Run the coverage npm run coverage

Output in the terminal

Because we specified HTML reported, we also get a coverage folder!

Coverage/index.html

From the coverage, we can see that we have about 87% code coverage! Which honestly is pretty good.

Closing thoughts

With test driven development, we can achieve high code quality, with high code coverage. This ensures that our app is always behaving as per expectation! No more manual testing or no more code breaking by doing some refactoring.

Even if you do not want to follow TDD, it is still good to write tests after you have implemented some functionalities. This way you are sure that any additional changes / refactoring, do not break the existing behavior of your app.

If you weren’t able to follow it exactly, you can view the full source code for this tutorial here.

Have fun coding!

Quick Code

Find the best tutorials and courses for the web, mobile…

Sign up for Developer Updates

By Quick Code

Receive weekly updates about new posts on programming, development, data science, web development and more Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Bilguun Batbold

Written by

Software Engineer

Quick Code

Find the best tutorials and courses for the web, mobile, chatbot, AR/VR development, database management, data science, web design and cryptocurrency. Practice in JavaScript, Java, Python, R, Android, Swift, Objective-C, React, Node Js, Ember, C++, SQL & more.

Bilguun Batbold

Written by

Software Engineer

Quick Code

Find the best tutorials and courses for the web, mobile, chatbot, AR/VR development, database management, data science, web design and cryptocurrency. Practice in JavaScript, Java, Python, R, Android, Swift, Objective-C, React, Node Js, Ember, C++, SQL & more.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store