typescript - NestJS enhetstesting av tjenesten: Mocking getManager som resulterer i feilen 'Connection "default" ble ikke funnet'


Jeg tester for øyeblikket enhetstesting av min NestJS-tjeneste. Min enhet kalles 'User', og jeg har etablert en grunnleggende tjeneste som lar meg samhandle med en MS SQL-server, med GET- og POST-endepunkter etablert i min Controller.

En av tjenestemetodene jeg prøver å etterligne er deleteV2-funksjonen, som du kan finne nedenfor:

// service file 
import { Injectable } from '@nestjs/common';
import { InjectConnection, InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { Connection, createConnection, EntityManager, getConnection, getManager, getRepository, Repository } from "typeorm";
import {User} from '../entities/user.entity';


@Injectable()
export class ServiceName {
  constructor(@InjectRepository(User) private usersRepository: Repository<User>,
              @InjectConnection() private connection: Connection,
              @InjectEntityManager() private manager: EntityManager
              ) {}

  async delete(id: number): Promise<any> {
    return await this.manager.delete(User, id);
  }
  async deleteV2(id: number): Promise<any> {
    return await getManager().delete(User, id);
  }

Merk at grunnen til at jeg har importert EntityManager OG injisert (med @InjectEntityManager()) en manager: EntityManager i tjenesten min, er den enkle årsaken at jeg ønsket å få litt mer øvelse med å jobbe med forskjellige metoder (jeg er en ny intern som jobber med NestJS). Faktumet at jeg har delete-metoden definert der jeg bruker den injiserte manager og deretter deleteV2-metoden definert der jeg bruker den importerte getManager er også rett og slett for å øve på enhetstesting med forskjellige metoder. Og det faktum at jeg injiserer Repository, Connection og EntityManager, er også av samme grunn.

I min spec.ts enhetstestfil for tjenesten har jeg:

// unit testing file for the service

type MockType<T> = { 
    [P in keyof T]?: jest.Mock<{}>;
};

describe('service tests', () => {
    const mockManagerFactory = jest.fn(() => ({
        delete: jest.fn().mockReturnValue(undefined),
    }))
 
    let service: ServiceName;
    // mock repository and mock connection also defined similarly to mockManager
    let mockManager: MockType<EntityManager>; 

    beforeEach(async () => {     
        const module: TestingModule = await Test.createTestingModule({
            providers: [
                ServiceName,
                // tokens for Repository and Connection are also provided along with their respective Factories
                {
                    provide: getEntityManagerToken(),
                    useFactory: mockManagerFactory,
                },
            ],
        }).compile();

        service = module.get<ServiceName>(ServiceName);
        // mockRepository and mockConnection also defined but not shown
        mockManager = module.get(getEntityManagerToken());
    });
})

Når jeg holder meg på den samme spec.ts-filen, definerte jeg flere tester. Den som forårsaker problemer er den som involverer deleteV2 nedenfor:

// same unit testing file for the service 
         
        // first test
        it('first test', async () => {
            expect(await service.delete(1000)).toEqual(undefined);
            expect(mockManager.delete).toBeCalled();
        });
        
        // second test 
        it('second test', async () => {
            expect(await service.deleteV2(1000)).toEqual(undefined);
            expect(mockManager.delete).toBeCalled();
        })

Mens den første testen ikke har problemer med å kjøre (den første testen er knyttet til delete i tjenestefilen), består ikke den andre testen (knyttet til deleteV2 i tjenestefilen) og resulterer i følgende feil:

● service tests › Service Functions › second test

ConnectionNotFoundError: Connection "default" was not found.

      at new ConnectionNotFoundError (error/ConnectionNotFoundError.ts:8:9)
      at ConnectionManager.Object.<anonymous>.ConnectionManager.get (connection/ConnectionManager.ts:40:19)
      at Object.getManager (index.ts:260:35)

Noen ideer om hvordan man kan håndtere denne feilen? Det virker som om å bruke getEntityManagerToken() fungerer med den injiserte manager, men ikke med getManager som er importert, siden deleteV2 bruker getManager mens delete (som består testen) bruker den importerte manager

Svar #1

Dette er hvor en stor fordel med å bruke avhengighetsinjeksjon kommer inn. @InjectEntityManager() injiserer bare objektet som (teoretisk) allerede har forbindelsen satt opp for deg, og du kan bare bruke metodene uten å bekymre deg om forbindelsen. Det gjør testing betydelig enklere (etter min mening). Med getMananger() må du bekymre deg for at TypeORM prøver å hente entity-manageren fra den aktive forbindelsen, som ikke burde være der i tester. Du kan mocke dette ved å bruke jest ved å bruke noe som følgende

const deleteMock = jest.fn();
jest.mock('typeorm', () => ({
  getManager: () => ({
    delete: deleteMock,
  })
}))

Dette fungerer godt nok, men jeg vil unngå å kalle metoder som getConnection og getManager fra TypeORM direkte hvis mulig.

Relaterte artikler