LoginSignup
2
0

More than 3 years have passed since last update.

NestJSでscope: Scope.Requestにしたサービスがあるとテストがコケる件

Last updated at Posted at 2020-03-25

Scope.Requestを使うケース

こういうの
https://qiita.com/rdlabo/items/7c25b711fa8db99512a6

起きること

@Injectable({
  scope: Scope.Request
})
class AwesomeService {...}

こういうサービスを使っているクラスのテストがコケる。

  ● Site Controller › list site api › should return items

    TypeError: Cannot read property 'loadCurrentUser' of undefined

      35 |   })
      36 |   public async listSites(): Promise<SiteResponseItemDTO[]> {
    > 37 |     const { Username: username } = this.cognito.loadCurrentUser();
         |     

DIしたはずのクラスがundefinedになっており、メソッドが見つからないというエラーが出る。

実動作について

yarn startsls offlineなどで動かす分には問題がない。
あくまでテストだけ。

対応方法:Scopeをdefaultにする

要はScopeをテストの時だけDefaultにすればOKです。

対応1: テストコードで上書きする

createTestingModuleする時にscopeを上書きしてやると、undefinedにならなくなります。

      const mod = await Test.createTestingModule({
        providers: [{
          provide: LoginService,
          useClass: LoginService,
          scope: Scope.DEFAULT
        }],
      }).compile();

対応2: module.getmodule.resolveにする

対応1で動かない場合、テスト対象クラスを取得する処理をgetからresolveに変えると動く場合もあります。

      const mod = await Test.createTestingModule({
        controllers: [AdminController],
        providers: [{
          provide: LoginService,
          useClass: LoginService,
          scope: Scope.DEFAULT
        }],
      }).compile();

      // Before
      const controller = mod.get<AdminController>(AdminController)

      // After
      const controller = await mod.resolve<AdminController>(AdminController)

対応3: 定義側で変える

@Injectableする時に環境変数で変えてしまうという手もあります。

@Injectable({
  // @See https://github.com/nestjs/nest/issues/2049#issuecomment-559959575
  scope: process.env.NODE_ENV === 'test' ? Scope.DEFAULT : Scope.REQUEST,
})
class AwesomeService {...}

そのほか

Scope.Requestの場合、module.getではなくawait module.resolveを使う必要がある。

      const mod = await Test.createTestingModule({
        providers: [LoginService],
      }).compile();

      // Error
      // LoginService is marked as a scoped provider.
      // Request and transient-scoped providers can't be used in combination with "get()" method.
      // Please, use "resolve()" instead.
      const service = mod.get<LoginService>(LoginService);

      // うごく
      service = await mod.resolve<LoginService>(LoginService)

参考

結構遭遇している人が多いみたい。
https://github.com/nestjs/nest/issues/2049

2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0