[Nest.js] e2e 테스트에서 @Cron() 서비스 중지시키기

Donghun Seol·2023년 4월 26일
0

0. 배경

기존의 api서버를 nest.js로 개선하는 작업을 진행중이다.
레거시 api가 있기 때문에 최소한의 컨트롤러만 구현해놓고 e2e 테스트를 작성한 뒤 기존의 api와 비교하면서 세부적인 구현을 할 생각이었다.

테스트코드 작성이 익숙하진 않아 레퍼런스를 찾아보면서 e2e테스트를 작성해 나갔다. 테스트는 성공했는데 심미성을 해치는 문제가 있었다.

1. 문제

batch.module.ts에 포함되어 있는 스케쥴러가 테스트가 끝나도 계속 동작하는 것이었다. 그 결과 매번 테스트 할 때마다 아래와 같은 에러메시지가 나왔다.

2. 시도와 실패

첫 번째는 나이브하게 시도했고 역시나 실패.

아래와 같이 생각했다.

  1. @nestjs/schedule의 스케쥴 모듈을 임포트해서 새로 설정한다.
  2. SchedulerRegistry의 deleteCronJob()을 활용해서 등록된 크론잡을 삭제
  3. 크론잡이 삭제되었으므로 테스트 내에서 호출되지 않는다.

그런데 새로 임포트한 모듈은 네스트 런타임에 의해 별도로 인스턴스화 된다. 이 인스턴스는 appModule안에 참조된 진짜 schedule 모듈과 다른 인스턴스가 된다. 따라서 삭제할 크론잡이 등록되어 있지 않으므로 삭제할 수 없었고 기존의 크론잡은 계속 호출되었다.

3. 해결

이리저리 찾아보다 해당 프로바이더를 테스트 시작 전에 오버라이드 하는 방식으로 해결했다.

아래의 overrideProvider 메서드를 통해 app이 참조하는 priceFeedService를 빈 객체로 덮어써버렸다. 따라서 이 객체는 아무런 동작을 하지 않고, 크론잡도 호출되지 않는다.

beforeEach(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    })
      .overrideProvider(PriceFeedService)
      .useValue({})
      .compile();
    app = moduleFixture.createNestApplication();

    await app.init();
  });
}

아래와 같이 깔끔하게 테스트가 종료된다.

4. 응용

e2e테스트에서 특정 모듈을 모킹해야 할 때 오버라이드가 유용해 보인다. 외부 api나 DB에 의존하는 서비스를 간단한 값을 돌려주는 객체로 재정의 하면 간결하고 조작가능한 테스트 코드를 작성할 수 있을것 같다.

계속 e2e 테스트를 작성해나가면서 이 방법을 적용해 볼 계획이다.

profile
I'm going from failure to failure without losing enthusiasm

0개의 댓글