함수의 호출 테스트하기 with jest.spyOn()
1. 개요
함수가 몇 번 호출되었는지, 어떤 인자를 받으며 호출되었는지 등에 대한 테스트 코드 작성 방법을 정리한다. 또한 아래의 등장하는 메서드들은 모두 mockFn에서만 사용이 가능하다. 즉, 진짜 함수에서는 사용하지 못한다. 하지만 jest.spyOn()을 이용하여 진짜 함수에서도 사용을 할 수 있다. 해당 방법도 정리한다.
2. .toHaveBeenCalled()
일반 함수가 아니라
mockFn에서만 사용가능 하다.
mockFn가 호출 되었는지 확인하는 메서드이다. 바로 코드를 작성해보자.
test('test', () => {
const add = (a, b) => a + b;
add(1, 2);
expect(add).toHaveBeenCalled();
});위의 테스트 결과를 예상해보자. 성공했을까? 그렇지 않다. 위의 테스트는 실패한다. 그 이유는 Matcher error 메시지에서 찾을 수 있다.
참고로
.toHaveBeenCalled()와 같은expect의 메서드가Matcher이다.

Matcher error를 보면 received value must be a mock or spy function이라는 문구를 볼 수 있다. 즉, 이를 정리하면 아래와 같다.
.toHaveBeenCalled()는 mockFn에서만 사용이 가능하다.
그럼 mockFn을 만들어 테스트를 진행해보자.
test('test', () => {
const add = (a, b) => a + b;
const mockFn = jest.fn(add);
mockFn(1, 2);
expect(mockFn).toHaveBeenCalled();
});
테스트가 정상적으로 동작하는 것을 확인할 수 있다.
호출을 하지 않을 경우의 테스트는 .not을 작성하면 된다. 아래는 해당 경우의 예시이다.
test('test', () => {
const add = (a, b) => a + b;
const mockFn = jest.fn(add);
expect(mockFn).not.toHaveBeenCalled();
});3. .toHaveBeenCalledTimes(number)
일반 함수가 아니라
mockFn에서만 사용가능 하다.
mockFn가 몇 번 호출되었는지 확인하는 메서드이다.
test('test', () => {
const add = (a, b) => a + b;
const mockFn = jest.fn(add);
mockFn(1, 2);
mockFn(2, 3);
expect(mockFn).toHaveBeenCalledTimes(2);
});Array.forEach() 메서드를 통해 테스트 코드를 작성해보자.
const helloEach = (fn, arr) => {
arr.forEach((name) => fn(name));
};
test('test', () => {
const hello = (name) => `Hello ${name}`;
const mockFn = jest.fn(hello);
helloEach(mockFn, ['HD', 'KH', 'GY']);
expect(mockFn).toHaveBeenCalledTimes(3);
});배열의 길이 만큰 mockFn이 호출되었다.
4. .toHaveBeenCalledWith(arg1, arg2, ...)
일반 함수가 아니라
mockFn에서만 사용가능 하다.
mockFn이 어떤 인자를 가지며 호출되었는지 확인하는 테스트이다.
const helloEach = (fn, arr) => {
arr.forEach((name) => fn(name));
};
test('test', () => {
const hello = (name) => `Hello ${name}`;
const mockFn = jest.fn(hello);
helloEach(mockFn, ['HD', 'KH', 'GY']);
expect(mockFn).toHaveBeenCalledWith('KH');
});.toHaveBeenCalledWith() 메서드의 인자는 mockFn의 예상된 인자들 중(위의 예시에선 "HD", "KH", "GY") 중 하나만 만족하면 된다.
5. .toHaveBeenLastCalledWith(arg1, arg2, ...)
일반 함수가 아니라
mockFn에서만 사용가능 하다.
mockFn의 마지막 호출에서 어떤 인자를 받으며 호출되었는지 확인하는 메서드이다. 바로 위의 예시를 조금 변형하여 테스트 코드를 작성해보자.
const introduceEach = (fn, arr) => {
arr.forEach(({ name, age }) => fn(name, age));
};
test('test', () => {
const introduce = (name, age) =>
`My name is ${name} and i'm ${age} years old`;
const mockFn = jest.fn(introduce);
introduceEach(mockFn, [
{ name: 'HD', age: 29 },
{ name: 'KH', age: 27 },
{ name: 'GY', age: 30 },
]);
expect(mockFn).toHaveBeenLastCalledWith('GY', 30);
});mockFn은 차례대로 name과 age이라는 인자를 받는다. 그리고 순서상 { name: 'GY', age: 30 }인자를 가진 mockFn이 가장 마지막에 호출이 된다.
6. .toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)
마지막에 호출된 mockFn의 인자를 확인하는 것이 아니라, 특정 순서에 호출된 mockFn의 인자를 확인하는 메서드이다.
const introduceEach = (fn, arr) => {
arr.forEach(({ name, age }) => fn(name, age));
};
test('test', () => {
const introduce = (name, age) =>
`My name is ${name} and i'm ${age} years old`;
const mockFn = jest.fn(introduce);
introduceEach(mockFn, [
{ name: 'HD', age: 29 },
{ name: 'KH', age: 27 },
{ name: 'GY', age: 30 },
]);
expect(mockFn).toHaveBeenNthCalledWith(2, 'KH', 27);
});7. jest.spyOn(object, methodName)
mocking에는 spy라는 개념이 있다. spy이는 말 그대로 스파이의 역할을 한다. 즉, 진짜 메서드의 정보를 몰래 빼내는 역할을 한다.
이를 이용하여 굳이 mockFn를 만들지 않고 메서드의 호출을 테스트할 수 있다.
예시를 통해 구체적인 사용을 알아보자.
test('test', () => {
const cal = {
add: (a, b) => a + b,
};
const spyFn = jest.spyOn(cal, 'add');
cal.add(1, 2);
cal.add(2, 3);
expect(spyFn).toHaveBeenCalledTimes(2);
expect(spyFn).toHaveBeenLastCalledWith(2, 3);
});어떤 메서드에 스파이를 달기 위해선 메서드는 객체에 포함되어 있어야 한다. 위의 예시에선 cal이라는 객체 내에 add 메서드가 있다. 이 add 메서드에 스파이를 달았다.
첫 번째 인자론 객체, 두 번째 인자론 문자열로 메서드 이름을 문자열로 넣으면 된다.
실제로 호출된 메서드는 cal.add()이고 이에 대한 정보를 몰래 캐고 있는 spyFn을 가지고 테스트를 진행하고 있다.
8. Conclusion
함수의 호출 테스트에 관련된 다양한
.toHaveBeen**메서드에 대해 알아보았다. 또한jest.spyOn()함수도 알아보았는데 이는 실제 테스트 코드를 작성할 때 유용하게 사용될 듯 하다. Jest에는 정말 다양한 메서드들이 존재한다. 많은 것들을 한 번에 정리하고 적용할 수 없지만 지금처럼 조금씩 꾸준히 학습을 이어나가도록 하자. 물론 실전에 적용도 필수이다!
출처
Last updated