【问题标题】:How to write unit test in nestjs and typeorm without connecting to db如何在不连接数据库的情况下在 Nestjs 和 typeorm 中编写单元测试
【发布时间】:2021-08-22 17:53:23
【问题描述】:

我不确定如何在不连接到 db 的情况下在 nestjs 和 typeorm 中实现单元测试。我尝试了一些技术,但似乎都不起作用。

我的模块看起来像这样。

import { HttpModule, Module } from '@nestjs/common'
import moment from 'moment';

import config from '@app/config'
import { OrdersService } from './services/order.service'
import { FraudOrderChecksService } from './services/fraud-order-checks.service'
import { FraudOrderChecksController } from './controllers/fraud-order-checks.controller'
import { HealthcheckController } from './controllers/healthcheck.controller';
import { TypeOrmModule } from '@nestjs/typeorm'
import { ormconfig } from './entities/ormconfig'


@Module({
    imports: [
        SharedModule,
        HttpModule,
        LoggerModule,
        ConfigModule.forRoot(config),
        TypeOrmModule.forRoot(ormconfig.luminskin as any),
        TypeOrmModule.forRoot(ormconfig.meridian as any),
        TypeOrmModule.forFeature([...ormconfig.luminskin.entities], 'luminskin'),
        TypeOrmModule.forFeature([...ormconfig.meridian.entities], 'meridian'),
        ...
    ],
    controllers: [
        MyController,
        ...
    ],
    providers: [
        ...
    ],
})
export class AppModule { }

我在测试中导入根模块

  beforeEach(async () => {
    jest.clearAllMocks();
    const module: TestingModule = await Test.createTestingModule({
      imports: [InternalModule]
    }).compile();
    ...
  });

当我尝试运行我的单元测试时,我得到了

[Nest] 93196   - 06/04/2021, 17:43:50   [ExceptionHandler] Unable to connect to the database (mydb). Retrying (1)...
AlreadyHasActiveConnectionError: Cannot create a new connection named "connectionname", because connection with such name already exist and it now has an active connection session.

如何将连接与根模块分离,使其仅在需要时运行。其实更清洁的技术也会被接受。

【问题讨论】:

  • 这里有一个大线程来回答这个问题:github.com/typeorm/typeorm/issues/1267
  • @MicaelLevi 看过,但我不确定这将如何在 Nestjs 中实现。任何指针都会有所帮助。
  • 我想说的是,不要导入整个 InternalModule,只需加载测试套件所需的提供程序或服务。或者,由于TypeOrmModule.forRoot 将尝试连接到您的数据库,您应该模拟'@nestjs/typeorm' 以使其在导入TypeOrmModule 类时返回您的测试替身。这个我还没试过

标签: unit-testing jestjs nestjs typeorm


【解决方案1】:

你不想对一个模块进行单元测试,你想对一个模块的单个组件进行单独的单元测试。

虽然您可以创建一个 TestModule 并像上面所做的那样简单地导入您的模块,但我只会在模块包含单个组件时才考虑这样做(即使那样我也不会这样做) '认为它不是很好的做法)。

您在测试中引入的组件越多:

  • 您需要管理的活动部件越多
  • 你要模拟的越多
  • 单元及其测试的可移植性较差
  • 您摄入的阿司匹林越多,尝试解决每次修改其父模块时出现的自我诱发的头痛

Nests TestingModule 使您能够以单独测试组件所需的最低限度“装配”一个独立的模块。它简化了您的测试设置和模拟创建/管理。

始终尝试将单元测试视为一个独立的、独立的过程。尽可能限制范围和依赖项,以使测试尽可能有效和简单。

这是我对服务进行单元测试的方法示例,其中我模拟了它的依赖项:

// app.service.spec.ts

describe('Testing app.service', () => {
  let module: TestingModule;
  let service: AppService;

  // mock out providers the service depends on
  const mockProviders = [
    {
      provide: ConfigService,
      useValue: {
        get: jest.fn().mockReturnValue('Mock!'),
      },
    },
  ];

  beforeAll(async () => {
    // build up testing module
    module = await Test.createTestingModule({
      imports: [],
      providers: [...mockProviders, AppService],
    })
      .compile()
      .catch((err) => {
        // Helps catch ninja like errors from compilation
        console.error(err);
        throw err;
      });

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

  it('Should return: Hello Mock!', async () => {
    const response = service.getHello();
    expect(response).toEqual('Hello Mock');
  });
});

我尝试将所有业务逻辑(尽可能)保留在服务中,让控制器轻松,通常保留用于 e2e 和/或集成测试。

这不是唯一的(甚至可能不是“最好的”)方法,但它可以帮助我让我的测试和服务更加专注。

【讨论】:

  • 幽默一下问题的原始前提。如果必须测试模块本身(例如,将整个应用程序作为测试运行以生成 OpenAPI 规范,例如 here),如何模拟 TypeOrmModule.forRoot... 调用?
猜你喜欢
  • 2020-04-29
  • 1970-01-01
  • 2021-01-14
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 2023-01-24
  • 1970-01-01
  • 2019-05-19
相关资源
最近更新 更多