mockImplementation

하기·2024년 11월 13일
0

요약: mockImplementation으로 \ 테스트하려는 것이 \ 사용하는 테스트 하면 안되는 것을 \ 테스트하는 파일에서 \ mock으로 바꿔서 사용하게 할 수 있다.

Jest Mock 처리 가이드

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  // 서비스 테스트 코드

1. 외부 API 호출 모듈 (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
};

2. 서비스 파일 (service.js)

service.js 파일에서는 apiModule.jsfetchData를 호출하여 데이터를 처리합니다.

// service.js
const { fetchData } = require('./apiModule');

async function getProcessedData() {
    const data = await fetchData(); // 외부 API 호출
    return `Processed: ${data.title}`;
}

module.exports = {
    getProcessedData
};

3. 서비스 테스트 파일 (tests/service.test.js)

테스트 파일에서는 jest.mock()을 사용해 apiModule.jsfetchData를 mock 처리합니다. 이렇게 설정하면 service.jsgetProcessedData 함수가 호출될 때 실제 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);
    });
});

코드 설명

1. jest.mock() 사용:

  • jest.mock('../apiModule')를 사용하여 apiModule 전체를 mock 처리합니다.
  • 이를 통해 fetchData 함수는 실제 API를 호출하지 않고, 테스트에서 설정한 mock 동작으로 대체됩니다.

2. mockImplementation 설정:

  • fetchData.mockImplementation(...)으로 fetchData 함수가 호출될 때 반환할 mock 데이터를 설정합니다.
  • 이 예제에서는 { title: 'Mocked Title' }이라는 객체를 반환하도록 했습니다. 실제 API 대신 이 데이터를 사용합니다.

3. 테스트 수행:

  • getProcessedData() 함수는 내부적으로 fetchData를 호출합니다. 하지만 fetchData는 mock 함수로 대체되었으므로 실제 API가 아닌, 우리가 설정한 mock 데이터를 반환하게 됩니다.
  • 이 mock 데이터를 기반으로 getProcessedData()가 예상한 결과를 반환하는지 검증합니다.

4. 호출 횟수 확인:

  • expect(fetchData).toHaveBeenCalledTimes(1);를 통해 fetchData가 실제로 한 번만 호출되었는지 검증합니다.

결론

이 방법을 사용하면 서비스 함수가 실제 API를 호출하는 대신, 테스트 중에 정의한 mock API를 사용하게 되어 다음과 같은 장점이 있습니다:

  • 테스트 속도 향상: 외부 API 호출이 없으므로 테스트가 빠르게 실행됩니다.
  • 테스트의 독립성: 외부 서버 상태에 의존하지 않고도 일관된 테스트 결과를 얻을 수 있습니다.
  • 비용 절감 및 안전성: 실제 API 호출이 없으므로 테스트 중에 불필요한 네트워크 비용이 발생하지 않으며, 실수로 실제 데이터를 변경할 위험이 없습니다.

이 방식은 외부 API뿐만 아니라 데이터베이스, 파일 시스템 접근 등 여러 의존성을 가진 코드에서 유용하게 활용할 수 있습니다.

쉽게 요약: mockImplementation으로 테스트하려는 것이 사용하는 테스트 하면 안되는 것을 테스트하는 파일에서 mock으로 바꿔서 사용하게 할 수 있다.



fetchData가 그 자체로 존재하는 게 아니라 apiModule내부에 있을 때, apiModule.mockImplementation을 사용한 모듈 Mock 처리

Jest에서 모듈 Mock 처리하기

파일 구조

project/
├── apiModule.js    // 외부 API 호출 모듈 (fetchData가 모듈의 메서드로 포함됨)
├── service.js      // API 모듈을 사용하는 서비스 코드
└── tests/
    └── service.test.js  // 서비스 테스트 코드

1. 외부 API 호출 모듈 (apiModule.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;

2. 서비스 파일 (service.js)

서비스 파일에서는 apiModule 모듈의 fetchData 메서드를 호출하여 데이터를 처리합니다.

// service.js
const apiModule = require('./apiModule');

async function getProcessedData() {
    const data = await apiModule.fetchData();  // 외부 API 호출
    return `Processed: ${data.title}`;
}

module.exports = {
    getProcessedData
};

3. 서비스 테스트 파일 (tests/service.test.js)

테스트 파일에서는 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);
    });
});

코드 설명

1. jest.mock()을 사용한 모듈 Mock 처리

  • jest.mock('../apiModule')을 통해 apiModule 전체를 mock 처리합니다.
  • 이로 인해 apiModule은 mock 객체가 됩니다.

2. mockImplementation을 사용한 fetchData 설정

  • apiModule.mockImplementation()을 통해 apiModulefetchData 메서드를 가진 mock 객체를 반환하도록 설정합니다.
  • fetchDatajest.fn()을 사용하여 mock 함수로 설정되며, mockImplementation으로 비동기로 { title: 'Mocked Title' } 데이터를 반환하도록 지정합니다.

다른 방법: fetchData가 apiModule내부에 있을 때, apiModule.fetchData.mockImplementation을 사용한 모듈 Mock 처리

Jest에서 모듈의 특정 메서드만 Mock 처리하기

fetchData 함수가 독립된 함수가 아니라 모듈의 메서드로 포함되어 있다고 가정하고, jest.mock()jest.fn()을 사용해 특정 모듈의 메서드만 mock 처리하는 방법을 설명합니다.

예제 시나리오

  • apiModule.js: 외부 API를 호출하는 모듈이며, 이 모듈 안에 fetchData 메서드가 포함되어 있습니다.
  • service.js: apiModule.jsfetchData 메서드를 호출하여 데이터를 처리하는 서비스 코드입니다.
  • service.test.js: 테스트 파일에서 jest.mock()jest.fn()을 사용해 apiModule.jsfetchData 메서드를 mock 처리하여 테스트를 수행합니다.

파일 구조

project/
├── apiModule.js    // 외부 API 호출 모듈 (fetchData가 모듈의 메서드로 포함됨)
├── service.js      // API 모듈을 사용하는 서비스 코드
└── tests/
    └── service.test.js  // 서비스 테스트 코드

1. 외부 API 호출 모듈 (apiModule.js)

이 예제에서는 fetchDataapiModule 객체의 메서드로 포함되어 있다고 가정합니다.

// 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;

2. 서비스 파일 (service.js)

서비스 파일에서는 apiModule 모듈의 fetchData 메서드를 호출하여 데이터를 처리합니다.

// service.js
const apiModule = require('./apiModule');

async function getProcessedData() {
    const data = await apiModule.fetchData(); // 외부 API 호출
    return `Processed: ${data.title}`;
}

module.exports = {
    getProcessedData
};

3. 서비스 테스트 파일 (tests/service.test.js)

테스트 파일에서 jest.mock()jest.fn()을 사용하여 apiModule.jsfetchData 메서드를 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);
    });
});

코드 설명

1. jest.mock()을 사용하여 모듈 전체를 mock 처리

  • jest.mock('../apiModule', () => ({ ...jest.requireActual('../apiModule'), fetchData: jest.fn() }));apiModule 모듈을 mock 처리하되, 모듈의 다른 함수나 속성은 유지하고, fetchData 메서드만 jest.fn()을 사용해 mock 함수로 대체합니다.
  • jest.requireActual('../apiModule')을 통해 apiModule의 실제 구현을 가져오고, 그 중 fetchData만 mock 처리하는 방식입니다.

2. apiModule.fetchData.mockImplementation 설정

  • 이제 fetchData Jest의 mock 함수가 되었으므로, mockImplementation을 사용하여 원하는 동작을 설정할 수 있습니다.
  • 이 예제에서는 { title: 'Mocked Title' }을 반환하도록 설정하여, 실제 API를 호출하지 않고 mock 데이터를 반환하게 했습니다.

0개의 댓글