최근 사이드 프로젝트에서 했던 고민들을 정리하는 시간을 가지고 있는데 몇몇 내용은 블로그에 올려도 좋겠다는 생각이 들어 이렇게 올리게 되었다.
사이드 프로젝트에서 이메일 인증 코드, 몇몇 api의 캐싱 용도로 redis를 사용하고 있는데 이러한 부분에 테스트를 붙일때 어떻게 할지에 대한 고민을 정리해보았다.
자바 스프링에서는 목킹하는 예시가 자주 보인다
혹은 embedded redis를 사용해서 테스트 하기도 한다
여러모로 테스트해본 결과 그냥 목킹해서 하는게 오히려 제일 편할수 있을거 같다
테스트 코드를 만들다 보니 redis를 mocking하는게 아니라 cache module에서 redis에 접근하고 cache module을 mocking하는게 편할 수도 있다는 결론이 나왔다
cache module에 redis 함수 자체를 제공하기 보다는 명확한 인터페이스를 만들어 기능을 분리하도록 하였다.
async setIntraAuthMailData(code: string, value: IntraAuthMailDto) {
await this.cacheManager.set<IntraAuthMailDto>(code, value, {
ttl: TIME2LIVE,
});
}
mocking은 다음과 같은 방식으로 하였다.
...
providers: [
IntraAuthService,
{
provide: MailerService,
useValue: {
sendMail: sendMailMock,
},
},
{
provide: CacheService,
useValue: {
setIntraAuthMailData: jest.fn(),
getIntraAuthMailData: jest.fn(),
del: jest.fn(),
},
},
],
...
위에서는 jest를 사용하여 mocking하였으나 테스트 코드 내부에서 내가 예상하는 결과를 만들어내기는 어려웠다.
그래서 jest.mock 보다 ts-mockito 사용하기 (feat. Node.js)
를 참고하여 ts-mockito를 적용해보았다
적용한 결과는 다음과 같다
const cacheService: CacheService = mock(CacheService);
const mailerService: MailerService = mock(MailerService);
...
providers: [
IntraAuthService,
{
provide: MailerService,
useValue: {
sendMail: mailerService.sendMail,
},
},
{
provide: CacheService,
useValue: instance(cacheService),
},
],
...
그리고 아래와 같이 사용하였다
when(cacheService.getIntraAuthMailData(mailCode)).thenResolve(
new IntraAuthMailDto(cadetUser.id, intraId),
);
위와 같은 when을 호출한 뒤에 실행되는 코드는 thenResoleve에 지정한 값을 리턴하도록 만들수 있다
jest로는 위와 같은 원하는 값을 리턴하도록 만드려면 spyOn을 사용하여야 했다
문제는 알아보기 어렵고 자동완성도 안되는 문자열로 함수 이름을 지정해야 했기에 불편함이 있었다
다행히 ts-mockito가 이러한 과정을 편하게 할 수 있도록 개선해줬고 지금까지 잘사용하고 있다
ts-mockito가 더이상 업데이트가 안 되는 상황이기는 하지만 큰 문제가 없는 한 계속 사용할 것 같다