Node, Nest, Deno/🦁 Nest - Series
Nest + Jest unit test (5) spy function, mockImplementation
DarrenKwonDev
2020. 12. 12. 20:58
jest.spyOn(object, methodName)
* spy 함수는 언제 사용해야 하나
toHaveBeenCalledTimes, toHaveBeenCalledWith 등을 사용할 때 expect 되는 메서드는 mock 된 것이거나 spy function이어야 합니다. 아무런 가공을 거치지 않은 일반 함수를 쓰게 되면 Matcher error: received value must be a mock or spy function 가 발생합니다.
이전까지는 mock을 사용해보았으나 spy function이 무엇인지는 살펴보지 않았습니다. spy function은 주로 mock을 할 수 없을 때 사용합니다.
언제 사용할 수가 없을까요? 테스팅해야 하는 함수가 테스트할 다른 함수 내에서도 사용되어 mocking을 할 경우 사용되는 함수를 테스트할 수 없기 때문에 원본은 두고 spy 해야 할 때가 있습니다.
쉽게 예시를 들어 보겠습니다.
deletePodcast 함수는 getPodcasat를 내부에 사용합니다. 이 경우 getPodcast를 mocking할 경우 getPodcast를 테스팅할수 없게 됩니다. 이런 경우에 spy를 사용합니다.
async getPodcast(id: number): Promise<PodcastOutput> {
try {
const podcast = await this.podcastRepository.findOne(
{ id },
{ relations: ['episodes'] },
);
if (!podcast) {
return {
ok: false,
error: `Podcast with id ${id} not found`,
};
}
return {
ok: true,
podcast,
};
} catch (e) {
console.log(e);
return this.InternalServerErrorOutput;
}
}
async deletePodcast(id: number): Promise<CoreOutput> {
try {
// deletePodcast는 getPodcast함수를 사용합니다. 따라서 getPodcast는 mocking해야 합니다.
const { ok, error } = await this.getPodcast(id);
if (!ok) {
return { ok, error };
}
await this.podcastRepository.delete({ id });
return { ok };
} catch (e) {
console.log(e);
return this.InternalServerErrorOutput;
}
}
jest
.spyOn(service, 'getPodcast')
.mockImplementation(async id => InternalServerErrorOutput);
* 그래서 spy 함수는 어떻게 사용하나
jest.spyOn으로 spy는 아래와 같이 진행할 수 있으며
mockImplementation을 통해서 해당 함수를 실행한다면 해당 스코프 내에서 mock을 한 것과 같은 효과를 냅니다. 실제 함수가 실행되는 것이 아니라 mockImplementation 내에 정의한 함수가 사용됩니다.
예시 1.
describe('deletePodcast', () => {
const ID = 1;
it('fail on getPodcast failed', async () => {
jest
.spyOn(service, 'getPodcast')
.mockImplementationOnce(async id => InternalServerErrorOutput);
const result = await service.deletePodcast(ID);
expect(result).toEqual(InternalServerErrorOutput);
});
});
예시 2.
describe('MailService', () => {
describe('sendVerificationEmail', () => {
it('should call sendEmail', () => {
const sendVerificationEmailArgs = {
to: 'email',
email: 'email',
code: 'code',
};
// sendEmail 함수를 spy합니다. mocking한다면 sendEmail 테스팅을 할 수 없을 것입니다
jest.spyOn(service, 'sendEmail').mockImplementation(async () => {});
service.sendVerificationEmail(
sendVerificationEmailArgs.to,
sendVerificationEmailArgs.email,
sendVerificationEmailArgs.code,
);
expect(service.sendEmail).toHaveBeenCalledTimes(1);
expect(service.sendEmail).toHaveBeenCalledWith('Verify Your Email', sendVerificationEmailArgs.to, 'ubereats', [
{ key: 'username', value: sendVerificationEmailArgs.email },
{ key: 'code', value: sendVerificationEmailArgs.code },
]);
});
});
});