Search code examples
testingcontrollerjestjstddnestjs

How to test controller, which has associations with another modules service? Nest.js


How should I test a controller, which has auth service and user service ? I am trying to follow TDD methodologies, from book, but it doesn't work like that anymore.

Any solutions?

This is a controller I want to test: auth.controller.ts

import { Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UserService } from '../user/user.service';

@Controller('auth')
export class AuthController {
  constructor(
    private readonly authService: AuthService,
    private readonly userService: UserService,
  ) {}
  @Post()
  async signup() {
    throw new Error('Not Implemented!');
  }

  @Post()
  async signin() {
    throw new Error('Not Implemented Error!');
  }
}

This is a service that will be used by auth controller to handle actions:auth.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class AuthService {}

This is external service that I will need to use in order to find and authenticate useruser.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class UserService {}

Here I am trying to do some TDD tests for auth controller:auth.controller.spec.ts

import { Test } from '@nestjs/testing';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { UserService } from '../user/user.service';

describe('EntriesController', () => {
  let authController: AuthController;
  let authSrv: AuthService;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      controllers: [AuthController],
      providers: [AuthService, UserService],
    })
      .overrideProvider(AuthService)
      .useValue({ signup: () => null, signin: () => null })
      .compile();

    authController = await module.get<AuthController>(AuthController);
    authSrv = await module.get<AuthService>(AuthService);
  });

  describe('signup', () => {
    it('should add new user to the database', async () => {
      expect(await authController.signin()).toBe(true);
      console.log(authController);
    });
  });

  describe('signin', () => {
    it('should sign in user, if credentials valid', async () => {});
  });
});


Solution

  • Instead of using overrideProvider you should be setting the mock directly in the providers array with something similar to this:

    beforeEach(async () => {
      const module = await Test.createTestingModule({
        controllers: [AuthController],
        providers: [
          {
            provide: AuthService,
            useValue: { signup: () => null, signin: () => null }
          },
          UserService
        ],
      })
      .compile();
    
      authController = await module.get<AuthController>(AuthController);
      authSrv = await module.get<AuthService>(AuthService);
    });
    

    The same should be done for UserService, this way you are creating true unit tests, only testing the immediate class and ignoring the rest. This repository of mine shows a lot of different testing examples for projects using NestJS. May be helpful to take a look.