typescript - Tilkoblingen "default" ble ikke funnet med NestJS enhetstesting av tjeneste


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.

Mens jeg var i stand til å lage en mock av Repository som brukes i tjenesten, klarte jeg ikke å etablere en mock getConnection i en metode som måtte kalle getConnection().

Når jeg prøvde enhetstesting med npm run test:watch, får jeg feilen ConnectionNotFoundError: Connection "default" was not found. Jeg har sett på (og faktisk hentet mye fra) How to stub EntityManager and Connection in TypeORM with Jest, men dette innlegget ser ikke ut til å utdype en tilkobling som ikke ble etablert, noe som er mitt problem.

Uansett, her er tjenesten min med de relevante delene:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { getConnection, Repository } from "typeorm";
import {User} from '../entities/user.entity';


@Injectable()
export class ServiceName {
  constructor(@InjectRepository(User) private usersRepository: Repository<User>) {}

  // Creating and inserting a new user into the database table using Repository
  // unit testing for this one works fine
  async createUserRepository(user: User): Promise<User> {
    const newUser = this.usersRepository.create(user); 
    return await this.usersRepository.save(newUser);
  }

  // Creating and inserting a new user into the database table using QueryBuilder and getConnection
  // unit testing for this one does not work so well 
  async createUserQueryBuilder(user: User): Promise<User> {
    await getConnection()
    .createQueryBuilder()
    .insert()
    .into(User)
    .values([
        user, 
     ])
    .execute();
    return user;  
  }

Og her er min spec.ts-fil for enhetstesting:

import { Test, TestingModule } from '@nestjs/testing';
import { ServiceName } from './app_codes_rms_area.service';
import { getRepositoryToken } from '@nestjs/typeorm';
import { User } from '../entities/user.entity';
import { Connection, Repository } from 'typeorm';

describe('service tests', () => {

    const repositoryMockFactory: () => MockType<Repository<any>> = jest.fn(() => ({ 
        create: jest.fn(),
        save: jest.fn(),
        // other functions
    }));

    const mockConnectionFactory = jest.fn(() => ({
        getConnection: jest.fn().mockReturnValue({
            createQueryBuilder: jest.fn().mockReturnThis(),
            getMany: jest.fn().mockReturnValue(allUsers),
            insert: jest.fn().mockReturnThis(),
            into: jest.fn().mockReturnThis(),
            values: jest.fn().mockReturnThis(),
            execute: jest.fn().mockReturnValue(user),
        })
    }));
 
    let service: ServiceName;
    let mockRepository: MockType<Repository<User>>;
    let mockConnection: Connection;

    beforeEach(async () => {
        const module: TestingModule = await Test.createTestingModule({
            providers: [
                ServiceName,
                {
                    provide: getRepositoryToken(User), // a User Repository is injected to the service 
                    useFactory: repositoryMockFactory, // using factory ensures that a new mock is used for every test
                },
                {
                    provide: Connection,
                    useFactory: mockConnectionFactory,
                }
            ],
        }).compile();

        service = module.get<ServiceName>(ServiceName);
        mockRepository = module.get(getRepositoryToken(User));
        mockConnection = module.get<Connection>(Connection);
    });
        it('should create a new user and return it using Repository', async () => {
            // some test that passes using mockRepository
        });

        it('should create a new user and return it using QueryBuilder (with mocked Connection)', async () => {
            expect(await service.createUserQueryBuilder(user)).toEqual(user);
            expect(mockConnection.createQueryBuilder).toBeCalled();
            expect(mockConnection.createQueryBuilder()['insert']).toBeCalled();
            expect(mockConnection.createQueryBuilder()['into']).toBeCalled();
            expect(mockConnection.createQueryBuilder()['values']).toBeCalled();
            expect(mockConnection.createQueryBuilder()['execute']).toBeCalled();
        })

Det er den andre testen, it('should create a new user and return it using QueryBuilder (with mocked Connection)', som utløser følgende feil:

  ● service tests › Service Functions › should create a new user and return it using QueryBuilder (with mocked Connection)

    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.getConnection (index.ts:252:35)
      at ServiceName.createUserQueryBuilder (somefile:19:11)
      at Object.it (somefile:134:34)

Svar #1

Den enkleste løsningen ville være å endre din createUserQueryBuilder-metode som vist nedenfor:

async createUserQueryBuilder(user: User): Promise<User> {
  await this.usersRepository
    .createQueryBuilder()
    .insert()
    .into(User)
    .values([
        user, 
     ])
    .execute();
  return user;  
}

Da kan du oppdatere depotets mock repositoryMockFactory:

const repositoryMockFactory: () => MockType<Repository<any>> = jest.fn(() => ({ 
  create: jest.fn(),
  save: jest.fn(),
  createQueryBuilder: jest.fn().mockReturnThis(),
  getMany: jest.fn().mockReturnValue(allUsers),
  insert: jest.fn().mockReturnThis(),
  into: jest.fn().mockReturnThis(),
  values: jest.fn().mockReturnThis(),
  execute: jest.fn().mockReturnValue(user),
}));

Oppdatering :

Basert på forespørselen din, kan du gjøre noe slikt også.

Oppdater din spec.ts-fil,

import * as typeorm from 'typeorm';

const getConnectionSpy = jest.spyOn(typeorm, 'getConnection');
getConnectionSpy.mockImplementation(() => ({
  createQueryBuilder: jest.fn().mockReturnThis(),
  getMany: jest.fn().mockReturnValue(allUsers),
  insert: jest.fn().mockReturnThis(),
  into: jest.fn().mockReturnThis(),
  values: jest.fn().mockReturnThis(),
  execute: jest.fn().mockReturnValue(user),
}));

Merk at du må oppdatere dine andre typeorm-importer tilsvarende. f.eks.: typeorm.Connection

Dette er bare for at du skal få en idé om hvordan du gjør det. Det kan være syntaksfeil siden jeg ikke testet dette.

Relaterte artikler