NodeJS: Creating code 100% testable with Jest and Factory pattern

Ben-Hur Santos Ott
5 min readDec 25, 2018
Image result for nodejs

Hello beloved warriors!

Today I want to purpose something different (maybe not so different, but new to me).

We are creating some nodejs apis in our project and we are using plain javascript for it. So, we face an issue that turned our code difficult to read: the cascading dependency injection.

Using dependency injection in typed languages is ok (like typescript, java, c#, etc). But for javascript it’s not so easy to handle.

We want to keep our code 100% covered but we need a way to split and test the code.

We decided to use, instead of classes, a folder split with factory pattern.

Ok, let’s understand a little bit about it. For this example, we will write a class that validates and persists a user model.

This is the traditional way: the UserService.

Ok, this is a simple one that receives via dependency injection the repository implementation.

This code doesn’t have big issues, but now let’s think about this same project, 6 months later… 8 injections, 40 methods, endless code…

If you want just to test one simple method inside this class, it could be a nightmare and you know it.

Now think about some time in the future:

We have a cascading problem here: what happens if the delete function calls the findById function to get the data and validate before delete?

You know: now you need to mock not only the dependencies for the delete function but for the findById as well, and so on.

Probably your class will have more than 1000 lines of code in the future and a single unit test could have 300 lines of code (easily).

And yes, this is a problem and I will tell you why: when you are late into the delivery and need to finish your tasks, you will look at the unit tests and your team will skip this with the excuse: we need to deliver, we will fix the unit test in the future.

You know this story…

What I want to purpose is: drop the class concept and adopt file splitting.

I’m not talking about to create multiple classes (like UserFindService, UserDeleteService, etc). I’m talking about export the functions!

Are you ready? Let’s Go!

First, we will create our project:

In the terminal, run:

mkdir my-node-proj
cd my-node-proj
npm init -y

Ok, now we will install the Jest:

npm install jest -D

Ok, just to be more declarative, how a normal project handle the service class pattern:

But remember:

  • The user-service now is a 1-year-old child (1500 lines of code)
  • The user-service.test.js have 3200 lines of code and the programmers right now don’t know if a test for a specific scenario exists or not =P.

Are you prepared for the mind blow?

In one image, I will show you how we split the code that help us to grow the application:

Ok, let me explain a little bit more about how we use this pattern.

First: the service function

We have 3 files:

  • <my-service-name>.<function-name>.factory.js: this file contains the logic for save the user.
  • <my-service-name>.<function-name>.test.js: this file contains all the unit tests for the factory.
  • index.js: this file will export our factory injecting the dependencies.

Let’s create the content of the factory:

This file handles only the save function.

Now we will create our first unit test, to cover the first rule: the name validation.

Inside the file user-service.save.tests.js:

Ok, with the unit test created, we will change our package.json to include the test command:

Now, run in the terminal:

npm test user-service.save.test

You will get this result:

Our function is 71.43% covered! We need to cover the lines 14 and 17 (red mark).

We covered the first part of the IF, but not the part that checks the string length. Let’s do it:

Nice! Now, let’s work a little bit with MOCKS.

For unit tests, we need to mock all our dependencies. The unique dependency for the save function is the persistUser. We will create a mock for it and we will check if it’s called in the right way.

We will create our last unit test that check if the persistUser is called and the result is ok:

You should realize that you don’t need to know the real implementation of the persistUser, just need to know how it was called. It helps in integration tests.

Running the test command again we can see now we are 100% covered!

Second: exporting the function to the application

Once all the mocks and the tests are encapsulated, we don’t need a cascade dependency injection anymore.

Let’s work on the index.js of that folder:

This file will export the constructed logic with real dependencies and will export it to the application:

Done! we have our service ready to use into the production environment!

Third: open a beer

--

--