Search code examples
typescripttestingjestjsnestjstypeorm

Nestjs service test with mock repository not working


I am testing Employee service in Nestjs with Typeorm. The service has a injected employees repository. My test strategy is to mock a simple repostiory for testing the service.

import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { getRepository, Repository } from 'typeorm';
import { CreateEmployeeDto } from './dto/create-employee.dto';
import { Employee } from './employee.entity';
import { EmployeesService } from './employees.service';
describe('EmployeesService', () => {
  let service: EmployeesService;

  const mockEmployeesRepository = {
    save: jest.fn().mockImplementation((dto: CreateEmployeeDto) => {
      return Promise.resolve({
        EmployeeID: Math.ceil(Math.random() * 10),
        ...dto,
      });
    }),
  };

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        EmployeesService,
        {
          provide: getRepositoryToken(Employee),
          useValue: mockEmployeesRepository,
        },
      ],
    }).compile();

    service = module.get<EmployeesService>(EmployeesService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
}

But I got EmployeesService › should be defined error. I just cannot figure out why EmployeesService not working in this simple test, even after check Inject TypeORM repository into NestJS service for mock data testing

more error message:

EmployeesService › should be defined

    expect(received).toBeDefined()

    Received: undefined

      35 |
      36 |   it('should be defined', () => {  
    > 37 |     expect(service).toBeDefined(); 
         |                     ^

employees.service.ts

@Injectable()
export class EmployeesService {
  constructor(
    @InjectRepository(Employee, 'db1')
    private employeesRepository: Repository<Employee>,
  ) {}

  findById(id: number): Promise<Employee> {
    return this.employeesRepository.findOneOrFail(id);
  }

  async createEmployee(createEmployeeDto: CreateEmployeeDto) {
    const newEmployee = createEmployeeDto;
    try {
      await this.employeesRepository.save(newEmployee);
    } catch (error) {
      throw new BadRequestException('Cannot create employee');
    }

    return newEmployee;
  }

  async deleteEmployee(id: number) {
    try {
      return await this.employeesRepository.delete(id);
    } catch (error) {
      throw new BadRequestException('Cannot delete employee');
    }
  }

  async updateEmployee(id: number, body: UpdateEmployeeDto) {
    const employee = this.employeesRepository.findOne(id);
    if (!employee) {
      throw new NotFoundException('Employee not found');
    }

    const updatedEmployee = await this.employeesRepository.update(id, body);

    return this.employeesRepository.findOne(id);
  }
}

Solution

  • This is your EmployeeService constructor:

    constructor(
        @InjectRepository(Employee, 'db1')
        private employeesRepository: Repository<Employee>,
      ) {}
    

    You are injecting two things but you are not passing both. You pass only one:

    const module: TestingModule = await Test.createTestingModule({
          providers: [
            EmployeesService,
            {
              provide: getRepositoryToken(Employee),
              useValue: mockEmployeesRepository,
            },
          ],
        }).compile();
    

    This module is an isolated DI container. You have to list what injected into the service