시나리오
서비스에서 회원가입 기능이 존재하는데, 회원가입에 성공하면 사용자에게 이메일과 문자를 보내서 알려주는 기능이 있다고 가정해보자.
이메일과 문자를 보내는 요청은 수행할 때마다 5원
, 10원
씩 발생하기 때문에 해당 요청은 모킹해서 처리해야 한다.
Jest
를 이용해서 모킹하는 여러 방법을 직접 사용해보고 특징을 이해해보고자 한다.
messageService.ts
다음은 이메일과 문자를 보내는 함수가 담긴 messageService.ts
파일의 내용이다:
export function sendEmail(email: string) {
console.log(`${email} 에 메일 전송 API 호출. 비용이 10원 소모되었습니다.`);
}
export function sendPhone(phone: string) {
console.log(`${phone} 에 문자 전송 API 호출. 비용이 5원 소모되었습니다.`);
}
userService.ts
다음은 회원가입 로직을 수행하는 함수가 담긴 userService.ts
파일의 내용이다:
import { sendEmail, sendPhone } from './messageService';
export interface IUser {
username: string;
email: string;
phone: string;
}
export function register(user: IUser) {
console.log(`${user.username} 님 가입을 환영합니다!`);
sendEmail(user.email);
sendPhone(user.phone);
return user;
}
1. 모킹하지 않는 경우
API 요청에 대한 모킹을 하지 않고 테스트를 수행할 때마다 비용이 계속 발생하는 방법이다.
소스 코드
import { register, IUser } from '../userService';
describe('회원 가입 기능 테스트', () => {
test('admin 회원 가입 테스트', () => {
const user: IUser = {
username: 'admin',
email: 'admin@example.com',
phone: '010-1111-2222',
};
expect(register(user)).toEqual(user);
});
});
실행 결과
admin 님 가입을 환영합니다!
admin@example.com 에 메일 전송 API 호출. 비용이 10원 소모되었습니다.
010-1111-2222 에 문자 전송 API 호출. 비용이 5원 소모되었습니다.
2. jest.fn() 사용
모킹이 필요한 부분들에 대해서 가짜 함수를 모두 정의해주는 방법이다.
함수를 일일히 정의해야 하기 때문에 번거로운 부분이 존재한다.
소스 코드
import { IUser } from '../userService';
describe('비용이 발생하는 요청을 모킹하고 회원 가입', () => {
const sendEmail = jest.fn<unknown, [string]>((email: string) => {
console.log(`${email} 에 메일을 보내는 가짜 API 를 실행했습니다. 비용이 들지 않습니다.`);
});
const sendPhone = jest.fn<unknown, [string]>((phone: string) => {
console.log(`${phone} 에 문자를 보내는 가짜 API 를 실행했습니다. 비용이 들지 않습니다.`);
});
const register = jest.fn((user: IUser) => {
console.log(
`${user.username} 님 가입을 환영합니다! 현재 모킹된 함수를 이용하고 있으므로 실제 요청은 발생하지 않습니다.`
);
sendEmail(user.email);
sendPhone(user.phone);
return user;
});
test('admin 회원 가입 테스트', () => {
const user: IUser = {
username: 'admin',
email: 'admin@example.com',
phone: '010-1111-2222',
};
register(user);
expect(sendEmail).toBeCalledTimes(1);
expect(sendEmail).toBeCalledWith(user.email);
expect(sendPhone).toBeCalledTimes(1);
expect(sendPhone).toBeCalledWith(user.phone);
});
});
실행 결과
admin 님 가입을 환영합니다! 현재 모킹된 함수를 이용하고 있으므로 실제 요청은 발생하지 않습니다.
admin@example.com 에 메일을 보내는 가짜 API 를 실행했습니다. 비용이 들지 않습니다.
010-1111-2222 에 문자를 보내는 가짜 API 를 실행했습니다. 비용이 들지 않습니다.
3. jest.mock() 사용
모듈 전체를 한꺼번에 모킹하는 방법이다.
register
함수 내부에서 sendEmail
, sendPhone
함수를 호출하고 있지만, 전부 모킹된 함수로 대체되어 동작하고 있기에 콘솔에 출력되는 메시지가 없는 것을 확인할 수 있다.
소스 코드
import { register, IUser } from '../userService';
import { sendEmail, sendPhone } from '../messageService';
jest.mock('../messageService');
describe('비용이 발생하는 요청을 모킹하고 회원 가입', () => {
test('admin 회원 가입 테스트', () => {
const user: IUser = {
username: 'admin',
email: 'admin@example.com',
phone: '010-1111-2222',
};
register(user);
expect(sendEmail).toBeCalledTimes(1);
expect(sendEmail).toBeCalledWith(user.email);
expect(sendPhone).toBeCalledTimes(1);
expect(sendPhone).toBeCalledWith(user.phone);
});
});
실행 결과
admin 님 가입을 환영합니다!