Jest는 외부 모듈을 쉽게 mock 처리할 수 있도록 설계되어 있어, 특정 API 호출을 테스트할 때 실제 API가 아닌, 테스트 중에 설정한 mock API가 호출되도록 만들 수 있습니다.
다음은 이 과정을 단계별로 설명한 예제입니다:
service.js
: 이 파일에서는 외부 API 호출이 포함된 apiModule.js
의 API 함수를 사용합니다.apiModule.js
: 실제 API를 호출하는 모듈입니다.service.test.js
: 테스트 코드에서는 jest.mock()
과 mockImplementation
을 사용해 apiModule.js
의 API 호출을 mock 처리합니다.project/
├── apiModule.js // 외부 API 호출 모듈
├── service.js // API를 사용하는 서비스 코드
└── tests/
└── service.test.js // 서비스 테스트 코드
apiModule.js
)먼저 외부 API 호출을 담당하는 apiModule.js
파일을 정의합니다.
// apiModule.js
const axios = require('axios'); // axios 사용 예제
// 실제 외부 API 호출
async function fetchData() {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
return response.data;
}
module.exports = {
fetchData
};
service.js
)service.js
파일에서는 apiModule.js
의 fetchData
를 호출하여 데이터를 처리합니다.
// service.js
const { fetchData } = require('./apiModule');
async function getProcessedData() {
const data = await fetchData(); // 외부 API 호출
return `Processed: ${data.title}`;
}
module.exports = {
getProcessedData
};
tests/service.test.js
)테스트 파일에서는 jest.mock()
을 사용해 apiModule.js
의 fetchData
를 mock 처리합니다. 이렇게 설정하면 service.js
의 getProcessedData
함수가 호출될 때 실제 API가 아닌 mock API가 실행됩니다.
// tests/service.test.js
const { getProcessedData } = require('../service');
const { fetchData } = require('../apiModule');
// apiModule을 mock 처리하여 fetchData가 실제 API를 호출하지 않도록 설정
jest.mock('../apiModule');
describe('Service with mocked API', () => {
it('should return processed data using mocked API response', async () => {
// fetchData의 mock 구현을 설정합니다.
fetchData.mockImplementation(async () => ({
title: 'Mocked Title', // 실제 API 대신 반환할 mock 데이터
}));
// getProcessedData 함수 호출
const result = await getProcessedData();
// 결과가 예상한 대로 처리되었는지 확인
expect(result).toBe('Processed: Mocked Title');
// fetchData가 실제로 한 번 호출되었는지 확인
expect(fetchData).toHaveBeenCalledTimes(1);
});
});
jest.mock()
사용:jest.mock('../apiModule')
를 사용하여 apiModule
전체를 mock 처리합니다.fetchData
함수는 실제 API를 호출하지 않고, 테스트에서 설정한 mock 동작으로 대체됩니다.mockImplementation
설정:fetchData.mockImplementation(...)
으로 fetchData
함수가 호출될 때 반환할 mock 데이터를 설정합니다.{ title: 'Mocked Title' }
이라는 객체를 반환하도록 했습니다. 실제 API 대신 이 데이터를 사용합니다.getProcessedData()
함수는 내부적으로 fetchData
를 호출합니다. 하지만 fetchData
는 mock 함수로 대체되었으므로 실제 API가 아닌, 우리가 설정한 mock 데이터를 반환하게 됩니다.getProcessedData()
가 예상한 결과를 반환하는지 검증합니다.expect(fetchData).toHaveBeenCalledTimes(1);
를 통해 fetchData
가 실제로 한 번만 호출되었는지 검증합니다.이 방법을 사용하면 서비스 함수가 실제 API를 호출하는 대신, 테스트 중에 정의한 mock API를 사용하게 되어 다음과 같은 장점이 있습니다:
이 방식은 외부 API뿐만 아니라 데이터베이스, 파일 시스템 접근 등 여러 의존성을 가진 코드에서 유용하게 활용할 수 있습니다.
project/
├── apiModule.js // 외부 API 호출 모듈 (fetchData가 모듈의 메서드로 포함됨)
├── service.js // API 모듈을 사용하는 서비스 코드
└── tests/
└── service.test.js // 서비스 테스트 코드
외부 API를 호출하는 apiModule.js
모듈을 정의합니다. 여기서는 fetchData
함수가 모듈의 메서드로 포함되어 있습니다.
// apiModule.js
const axios = require('axios');
// 실제 외부 API 호출을 포함한 모듈
const apiModule = {
async fetchData() {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
return response.data;
},
};
module.exports = apiModule;
서비스 파일에서는 apiModule
모듈의 fetchData
메서드를 호출하여 데이터를 처리합니다.
// service.js
const apiModule = require('./apiModule');
async function getProcessedData() {
const data = await apiModule.fetchData(); // 외부 API 호출
return `Processed: ${data.title}`;
}
module.exports = {
getProcessedData
};
테스트 파일에서는 jest.mock()
을 사용하여 apiModule
전체를 mock 처리하되, mockImplementation
을 사용해 fetchData
메서드를 mock 데이터와 연결합니다.
// tests/service.test.js
const { getProcessedData } = require('../service');
const apiModule = require('../apiModule');
// apiModule을 mock 처리하여 fetchData 메서드가 실제 API를 호출하지 않도록 설정
jest.mock('../apiModule'); // apiModule의 전체 구현을 mock으로 대체
apiModule.mockImplementation(() => ({
fetchData: jest.fn(async () => ({
title: 'Mocked Title', // 실제 API 대신 반환할 mock 데이터
})),
}));
describe('Service with mocked API', () => {
it('should return processed data using mocked API response', async () => {
// getProcessedData 함수 호출
const result = await getProcessedData();
// 결과가 예상한 대로 처리되었는지 확인
expect(result).toBe('Processed: Mocked Title'); // 예상한 mock 데이터에 맞는 결과 확인
// fetchData가 실제로 한 번 호출되었는지 확인
expect(apiModule.fetchData).toHaveBeenCalledTimes(1);
});
});
jest.mock('../apiModule')
을 통해 apiModule
전체를 mock 처리합니다.apiModule
은 mock 객체가 됩니다.apiModule.mockImplementation()
을 통해 apiModule
이 fetchData
메서드를 가진 mock 객체를 반환하도록 설정합니다.fetchData
는 jest.fn()
을 사용하여 mock 함수로 설정되며, mockImplementation
으로 비동기로 { title: 'Mocked Title' }
데이터를 반환하도록 지정합니다.fetchData
함수가 독립된 함수가 아니라 모듈의 메서드로 포함되어 있다고 가정하고, jest.mock()
과 jest.fn()
을 사용해 특정 모듈의 메서드만 mock 처리하는 방법을 설명합니다.
apiModule.js
: 외부 API를 호출하는 모듈이며, 이 모듈 안에 fetchData
메서드가 포함되어 있습니다.service.js
: apiModule.js
의 fetchData
메서드를 호출하여 데이터를 처리하는 서비스 코드입니다.service.test.js
: 테스트 파일에서 jest.mock()
과 jest.fn()
을 사용해 apiModule.js
의 fetchData
메서드를 mock 처리하여 테스트를 수행합니다.project/
├── apiModule.js // 외부 API 호출 모듈 (fetchData가 모듈의 메서드로 포함됨)
├── service.js // API 모듈을 사용하는 서비스 코드
└── tests/
└── service.test.js // 서비스 테스트 코드
이 예제에서는 fetchData
가 apiModule
객체의 메서드로 포함되어 있다고 가정합니다.
// apiModule.js
const axios = require('axios');
// 실제 외부 API 호출을 포함한 모듈
const apiModule = {
async fetchData() {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
return response.data;
},
};
module.exports = apiModule;
서비스 파일에서는 apiModule
모듈의 fetchData
메서드를 호출하여 데이터를 처리합니다.
// service.js
const apiModule = require('./apiModule');
async function getProcessedData() {
const data = await apiModule.fetchData(); // 외부 API 호출
return `Processed: ${data.title}`;
}
module.exports = {
getProcessedData
};
테스트 파일에서 jest.mock()
과 jest.fn()
을 사용하여 apiModule.js
의 fetchData
메서드를 mock 처리합니다.
// tests/service.test.js
const { getProcessedData } = require('../service');
const apiModule = require('../apiModule');
// apiModule 모듈을 mock 처리하여 fetchData 메서드가 실제 API를 호출하지 않도록 설정
jest.mock('../apiModule', () => ({
...jest.requireActual('../apiModule'), // 실제 모듈의 다른 함수 및 속성을 유지
fetchData: jest.fn(), // fetchData만 mock 처리
}));
describe('Service with mocked API', () => {
it('should return processed data using mocked API response', async () => {
// fetchData의 mock 구현을 설정합니다.
apiModule.fetchData.mockImplementation(async () => ({
title: 'Mocked Title', // 실제 API 대신 반환할 mock 데이터
}));
// getProcessedData 함수 호출
const result = await getProcessedData();
// 결과가 예상한 대로 처리되었는지 확인
expect(result).toBe('Processed: Mocked Title'); // 예상한 mock 데이터에 맞는 결과 확인
// fetchData가 실제로 한 번 호출되었는지 확인
expect(apiModule.fetchData).toHaveBeenCalledTimes(1);
});
});
jest.mock('../apiModule', () => ({ ...jest.requireActual('../apiModule'), fetchData: jest.fn() }));
는 apiModule
모듈을 mock 처리하되, 모듈의 다른 함수나 속성은 유지하고, fetchData
메서드만 jest.fn()
을 사용해 mock 함수로 대체합니다.jest.requireActual('../apiModule')
을 통해 apiModule
의 실제 구현을 가져오고, 그 중 fetchData
만 mock 처리하는 방식입니다.fetchData
Jest의 mock 함수가 되었으므로, mockImplementation
을 사용하여 원하는 동작을 설정할 수 있습니다.{ title: 'Mocked Title' }
을 반환하도록 설정하여, 실제 API를 호출하지 않고 mock 데이터를 반환하게 했습니다.