ngATL Conference Atlanta, GA

NestJS on 2018 ngATL Conference Atlanta, GA

NestJS 2018 ngATL

LEARN MORE

Unit Testing

Unit tests are very important in the art of programming. There's a lot of great articles why and how we should write them, thus here I'm gonna show you only the Nest specific tools.

Isolated tests

Components, controllers, interceptors.. every Nest application building block is in fact just a simple class. Since each dependency is injected through the constructor, you can easily mock them using abilities of the popular libraries, for example Jasmine or Jest.

cats.controller.spec.ts
JavaScript TypeScript
TypeScript

import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

describe('CatsController', () => {
  let catsController: CatsController;
  let catsService: CatsService;

  beforeEach(() => {
    catsService = new CatsService();
    catsController = new CatsController(catsService);
  });

  describe('findAll', () => {
    it('should return an array of cats', async () => {
      const result = ['test'];
      jest.spyOn(catsService, 'findAll').mockImplementation(() => result);

      expect(await catsController.findAll()).toBe(result);
    });
  });
});
TypeScript

import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

describe('CatsController', () => {
  let catsController;
  let catsService;

  beforeEach(() => {
    catsService = new CatsService();
    catsController = new CatsController(catsService);
  });

  describe('findAll', () => {
    it('should return an array of cats', async () => {
      const result = ['test'];
      jest.spyOn(catsService, 'findAll').mockImplementation(() => result);

      expect(await catsController.findAll()).toBe(result);
    });
  });
});
Hint Keep your test files nearby tested classes. The testing files should have a .spec or .test suffix.

Here's an example which is using Jest library. We created the instances of the both CatsController and the CatsService manually, using the new keyword. We didn't use any Nest utility. This type of testing is called isolated tests.

Testing utilities

Nest has a special package @nestjs/testing, which gives a set of utilities to boost the testing process. Let's rewrite the example to make use of Nest Test static class.

cats.controller.spec.ts
JavaScript TypeScript
TypeScript

import { Test } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

describe('CatsController', () => {
  let catsController: CatsController;
  let catsService: CatsService;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
        controllers: [CatsController],
        components: [CatsService],
      }).compile();

    catsService = module.get<CatsService>(CatsService);
    catsController = module.get<CatsController>(CatsController);
  });

  describe('findAll', () => {
    it('should return an array of cats', async () => {
      const result = ['test'];
      jest.spyOn(catsService, 'findAll').mockImplementation(() => result);

      expect(await catsController.findAll()).toBe(result);
    });
  });
});
TypeScript

import { Test } from '@nestjs/testing';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

describe('CatsController', () => {
  let catsController;
  let catsService;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
        controllers: [CatsController],
        components: [CatsService],
      }).compile();

    catsService = module.get(CatsService);
    catsController = module.get(CatsController);
  });

  describe('findAll', () => {
    it('should return an array of cats', async () => {
      const result = ['test'];
      jest.spyOn(catsService, 'findAll').mockImplementation(() => result);

      expect(await catsController.findAll()).toBe(result);
    });
  });
});

The Test class has a createTestingModule() method which takes as an argument the module metadata (same object as the @Module() decorator). This method creates a TestingModule instance, which in turn provides a few methods, but only one of them is useful within the unit testing - the compile(). This function is asynchronous, so it has to be awaited. When the module would be compiled and ready to use, you might retrieve any instance using get() method.

Sometimes you might want to use test doubles instead of real instances. It's easy because Nest permits to override the component using custom components.

Hint Read more about the TestingModule class here.

Sponsors

Nest is an MIT-licensed open source project. It can grow thanks to the support by these awesome people. If you'd like to join them, please read more here. Thanks!

Become a sponsor