Nestjs overrideProvider 与单元测试中的提供程序

Vah*_*afi 9 unit-testing nestjs nestjs-testing

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

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

以及方法的另一种方式overrideProvider。如下:

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

有什么不同?

Jay*_*iel 9

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

const modRef = await Test.createTestingModule({
  import: [AuthModule]
}).compile();
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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


M U*_*M U 6

区别很简单。

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

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

结果是完全相同的 - 你的模拟被注入到 的构造函数中UserService

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

存储库并不是用来解释的好例子,但请考虑一下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();
Run Code Online (Sandbox Code Playgroud)

我希望这是清楚的。如果没有,请发表评论,我会尽力解释更多。