2

我在 NestJS 中看到了两种模拟服务以进行单元测试的方法,第一种与我们在真实模块中定义提供者的方式相同,例如:

const module = await Test.createTestingModule({
  providers: [
    UserService,
    {
      provide: getRepositoryToken(User),
      useValue: mockUsersRepository,
    }
  ],
}).compile();

另一种方法是overrideProvider方法。如下:

const module = await Test.createTestingModule({
  imports: [UserModule]
})
.overrideProvider(getRepositoryToken(User))
.useValue(mockUsersRepository)
.compile();

有什么区别?

4

2 回答 2

3

区别很简单。

使用第一种方法(提供程序数组),您可以创建自定义测试模块来测试(可能)UserService.

使用第二种方法,您可以使用与应用程序本身相同形状的完整模块。

结果是完全一样的——你的模拟被注入到UserService.

第一种方法更适合小型的,主要是单元测试,但这些测试也可以在完全不使用 NestJS 测试工具的情况下完成(只需手动将 mock 传递给 ctor),而第二种方法在集成测试中做得很好。

Repository 不是用来解释的好例子,但想想Logger. 您正在执行 2 个或更多模块的一些集成测试。您不想手动创建大的测试模块(这也破坏了与模块的真实形状的联系),但您只想导入正在一起测试的模块,例如.overrideProvider,它可以让您断言所有记录器调用跨所有测试模块。LoggerloggerMock

例子:

@Module({providers: [LoggerService], exports: [LoggerService]})
export class LoggerModule {}

@Module({imports: [LoggerModule], providers: [FooService]})
export class FooModule {}

@Module({imports: [LoggerModule], providers: [BarService]})
export class BarModule {}

@Module({imports: [FooModule, BarModule]}
export class AppModule {}

// TEST
const testModule = await Test.createTestingModule({
  import: [AppModule]
})
  .overrideProvider(LoggerService)
  .useValue(/* your logger mock will be provided in both FooService and BarService and you can easily test all related to logs then */)
  .compile();

我希望很清楚。如果没有,请发表评论,我将尝试解释更多。

于 2021-08-31T15:32:38.363 回答
2

因此,让我尝试以这种方式解释它: overrideProvider当您导入整个模块并需要覆盖它作为提供者的某些内容时很有用。一个用例,就像提到的答案一样,将覆盖记录器。所以说你有

const modRef = await Test.createTestingModule({
  import: [AuthModule]
}).compile();

并假设AuthModuleimports: [ LoggerModule ]。在我们的测试中,我们真的不想看到所有创建的日志,但是我们不能为 提供自定义提供程序,LoggerService因为它是通过 导入和使用的LoggerModule(覆盖注入令牌并不是真正的常见做法)。因此,为了提供我们自己的实现LoggerService(假设我们只需要一个 nooplog方法),我们可以执行以下操作

const modRef = await Test.createTestingModule({
  import: [AuthModule]
})
  .overrideProvider(LoggerService)
  .useValue({ log: () => { /* noop */ } })
  .compile();

现在,当我们AuthService调用this.logger.log()它时,它只会调用它noop并完成它。

另一方面,如果我们在进行单元测试,通常您不需要这样做,因为您只需直接在测试模块的元数据中overrideProvider设置和自定义提供程序并使用它。provider

当您必须使用(例如集成和 e2e 测试)时,它overrideProvider非常有用,否则,通常最好使用自定义提供程序imports

于 2021-09-01T19:27:49.163 回答