728x90
반응형
Mocking (모킹)
(mock: 모조품)
테스트할 때 의존하는 내부 또는 외부 요소를 가짜로 만들어 사용하는 방식입니다. 모킹은 실제 객체를 사용하지 않고, 해당 객체의 동작만을 흉내냄으로써 테스트를 독립적으로 수행할 수 있도록 합니다.
- 모킹의 활용성: 테스트뿐만 아니라 로컬 개발 환경에서도 생산성을 높입니다. 예를 들어, JSONPlaceholder와 같은 가짜 API를 사용해 빠르게 테스트할 수 있습니다.
- 독립적인 테스트: 상용 API, 데이터베이스, 라이브러리 등의 의존성 없이 코드의 동작을 독립적으로 테스트할 수 있습니다. 이는 테스트의 신뢰성을 높여줍니다.
- 모킹의 필요성: 모킹을 사용하지 않으면 테스트 시간이 길어지고, 모든 인터페이스가 구현된 환경에서 테스트를 수행해야 하는 번거로움이 생깁니다. 필요한 경우 모킹을 적절히 활용하는 것이 효율적인 테스트 방법입니다.
Mock의 장단점
- 장점
- 독립성: 외부 리소스에 의존하지 않고 테스트할 수 있어 안정성이 높아집니다.
- 속도 향상: 외부 API나 데이터베이스 호출 없이 테스트가 가능하므로 빠르게 테스트를 진행할 수 있습니다.
- 일관성: 테스트 결과를 예측하기 쉬우며, 오류 상황을 쉽게 시뮬레이션할 수 있습니다.
- 단점
- 실제 환경과의 차이: 실제 실행 환경과 다른 조건에서 테스트를 수행하기 때문에, 테스트와 실제 시스템 간의 동작이 다를 수 있습니다.
목 객체 용어 (책 내용)
- 스텁(Stub): 테스트를 위해 특정 의존성을 대체하는 객체입니다. (대역)
- 주로 의존하고 있는 컴포넌트에서 테스트하기 어려운 부분이 있을 때 사용합니다.
- Jest에서는 목 모듈 API를 사용하여 특정 모듈이나 라이브러리를 스텁으로 대체합니다.
- 예시: 웹 API에 의존하는 로직을 테스트할 때, ‘웹 API가 특정 값을 반환 했을 때 이렇게 동작해야 한다’는 식으로 테스트를 수행할 수 있습니다.
jest.mock("next/router", () => require("next-router-mock"));
- 스파이(Spy): 호출된 함수의 기록을 검증하는 데 사용됩니다.
- Jest에서는 목 함수 API를 사용하여 함수 호출 및 전달된 인수를 기록합니다.
- 예시: 콜백 함수가 의도한 대로 호출 되었는지, 호출된 횟수나 인수를 기록하여 테스트할 수 있습니다.
Mock을 활용하는 상황들
- API 응답 테스트: 실제 외부 서버나 API에 요청을 보내는 대신, 가짜 응답을 만들어 테스트합니다.
- 의존성 격리: 테스트하려는 모듈이 다른 모듈에 의존하는 경우, 해당 의존성을 mock으로 대체하여 해당 모듈만 집중적으로 테스트합니다.
- 특정 상황 가정: 테스트 환경에서 조건을 설정하고 특정 상황을 가정한 상태에서 동작을 테스트합니다.
Mock 테스트 예시 코드
1. 특정 API를 Mocking
Jest의 목 모듈 jest.mock을 사용하여 외부 API를 대체합니다. https://jestjs.io/docs/mock-functions#mocking-modules
import axios from 'axios';
class Users {
static all() {
return axios.get('/users.json').then(resp => resp.data);
}
}
export default Users;
import axios from 'axios';
import Users from './users';
jest.mock('axios');
test('should fetch users', () => {
const users = [{name: 'Bob'}];
const resp = {data: users};
axios.get.mockResolvedValue(resp);
// or you could use the following depending on your use case:
// axios.get.mockImplementation(() => Promise.resolve(resp))
return Users.all().then(data => expect(data).toEqual(users));
});
2. 특정 함수를 Mocking
jest.fn 이나 jest.spyOn 를 사용하여 함수 호출을 모킹하고 검증합니다.
test('mock 함수 호출 테스트', () => {
const mockFunction = jest.fn(() => 'Hello');
mockFunction();
expect(mockFunction).toHaveBeenCalled();
expect(mockFunction).toHaveBeenCalledTimes(1); // 호출 횟수 검증
expect(mockFunction).toReturnWith('Hello'); // 반환값 검증
});
test('더미 함수 테스트', () => {
const myMockFunction = jest.fn().mockImplementation((x) => x * 2);//더미함수정의
expect(myMockFunction(2)).toBe(4);
expect(myMockFunction(3)).toBe(6);
});
// 예제 객체와 메서드
const user = {
setName(name) {
console.log(`User's name is set to ${name}`);
return name;
},
};
test('setName 메서드 호출 여부를 스파이로 검증', () => {
// user 객체의 setName 메서드를 스파이로 감시 시작!
const spy = jest.spyOn(user, 'setName');
// setName 메서드 호출
user.setName('Alice');
// setName 메서드가 'Alice'라는 인수로 호출되었는지 검증
expect(spy).toHaveBeenCalledWith('Alice');
// setName 메서드가 정확히 한 번 호출되었는지 검증
expect(spy).toHaveBeenCalledTimes(1);
// 원래 메서드의 동작을 유지하므로 반환값도 확인 가능
expect(spy).toHaveReturnedWith('Alice');
// 스파이한 메서드를 원래 상태로 복구
spy.mockRestore();
});
3. 타이머 Mocking
setTimeout, setInterval 같은 타이머 함수의 동작을 모킹하여 테스트합니다.
이러한 타이머 관련 web api들은 실시간 시간 경과에 의존성을 가지기 때문에, 시간 경과를 제어하며 테스트해야 한다.
jest.useFakeTimers();
test('타이머 호출 테스트', () => {
const callback = jest.fn();
// 1초 후에 callback 함수가 호출되도록 설정
setTimeout(callback, 1000);
// 아직 시간이 지나지 않았으므로 callback이 호출되지 않음
expect(callback).not.toHaveBeenCalled();
// 1000ms 경과 시킴
jest.advanceTimersByTime(1000);
// 이제 callback이 한 번 호출되었는지 검증
expect(callback).toHaveBeenCalled();
expect(callback).toHaveBeenCalledTimes(1);
jest.clearAllTimers(); // 타이머 상태 초기화
});
test('setInterval을 사용한 타이머 mock 테스트', () => {
const callback = jest.fn();
// 500ms마다 callback 함수 호출
setInterval(callback, 500);
// 1000ms가 경과한 상태에서 callback이 두 번 호출되었는지 확인
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalledTimes(2);
jest.clearAllTimers(); // 타이머 상태 초기화
});
반응형
'Engineering > etc.' 카테고리의 다른 글
px, em, rem 차이를 알아보자 (2) | 2022.12.18 |
---|---|
0316_Web page를 꾸미는 역할, CSS (0) | 2020.03.16 |
0315_First step to Web, Summary about HTML (0) | 2020.03.16 |