jest mock 함수

2021. 3. 20. 07:08javascript/테스팅

jest mock 함수

영어 단어의 의미로 mock을 알아보면 가짜이다. 엥 가짜함수? 이게 뭘까... 여기서 가짜 함수란 테스트하기 위해 모의로 만든 함수라고 생각하면 된다. 

 

실제 구현된 코드를 모의 코드로 변경하여 편리하게 테스팅을 할 수 있다. 

 

mock 함수만들어보기

const mockFn = jest.fn();

 

jest.fn();를 이용하여 mock 함수를 만들 수 있다. mock함수 안에는 입력값을 넣어줄 수 있는데 이 값은 mockFn의 mock이라는 인스턴스에서 확인할 수 있다. 

 

mockFn();
mockFn('하위');

test('mock Function', () => {
    console.log(mockFn.mock.calls);
    expect("mock").toBe("mock");
});

mock.calls라는 값을 console로 찍어보게 되면 아래와 같이 결과가 나오게 된다. 

 

 

mockFn에 각 입력으로 넣어준 값들을 배열형태로 확인할 수 있다. 당연하지만 해당 값에 접근할 때 [0][1]과 같은 방식으로 접근하면 된다. 

mockFn(11);
mockFn(21);

test('mock Function', () => {
    expect(mockFn.mock.calls[0][0]).toBe(11);
});

 

또는 mockFn() 함수가 호출될 때 특정 값이 반환되게 만들어줄 수 있습니다. 

 

mockFn
.mockReturnValueOnce(10)
.mockReturnValueOnce(20)
.mockReturnValueOnce(30)
.mockReturnValue(40);

mockFn();
mockFn();
mockFn();
mockFn();

 

위의 mockReturnValueOnce, mockReturnValue는 mockFn()함수가 호출될때 지정된 반환 값이다. 아래와 같이 호출을 진행하게되면 mock.calls 및 results에 값이 기록되게 된다. 

 

console.log(mockFn.mock.results);

위와 같이 로그를 찍게되면 아래와 같이 값이 등록된 것을 확인할 수 있다. 

 

 

mock 비동기 함수

mockResolvedValue를 이용하여 name, age, gender를 갖고 있는 새로운 객체를 넘겨 주었고 ResolvedValue를 통해 그 값을 newUser롤 받아와 나타낼 수 있다. 

mockFn.mockResolvedValue({name:'hoony', age:25, gender: 'man'});

test('async test', () => {
    mockFn().then(newUser => {
        expect(newUser.age).toBe(25);
    });
});

 

 

외부 모듈 mock 함수 만들어주기

외부 모듈을 mock함수에 등록해서 실제 외부 모듈 함수를 실행되지 않고 등록된 값이 반환되게 바꿀 수 있다. 자세한건 예제를 보자.

.//hi.js
createNewUser:(name, age, gender) => {
        console.log('유저가 성공적으로 생성이 완료되었습니다');
        return {
            name, 
            age, 
            gender
        }
    }

// test.js
const fn = require("./hi");
jest.mock("./hi");

fn.createNewUser.mockReturnValue({name:'hoony', age:25, gender:"man"});

위의 코드를 보면 jest.mock에 fn과 같은 js 파일을 등록해주었다. 등록해준 후 createNewUser를 보면 console.log()를 통해 해당함수가 실행되었음을 볼 수 있고 name, age, gender등을 받아서 반환해줌을 알 수 있다. 

 

fn에 mock에 해당하는 함수를 등록 후 mockReturnValue에 반환될 값을 설정해줄 수 있다. 이런식으로 설정해주면 fn.createValue를 불러오면 createNewUser에 위치한 console.log는 작동하지 않으며 등록한 json이 반환되는 것을 알 수 있다. 

test('async test', () => {
    const newUser = fn.createNewUser();
    console.log(newUser);
    expect(newUser.name).toBe("hoony");
});

 

 

 

만약 아래 부분을 지우면 어떻게 될까?

jest.mock("./hi");

fn.createNewUser.mockReturnValue({name:'hoony', age:25, gender:"man"});

 

로그를 확인해보면 실제 외부 모듈이 실행된 것을 확인할 수 있다. 

const fn = require("./hi");

test('async test', () => {
    const newUser = fn.createNewUser('hoony', 25, "man");
    console.log(newUser);
    expect(newUser.name).toBe("hoony");
});

 

 

이번 예제를 통해 외부 모듈을 등록 후 test를 진행해주면 실제로 해당 함수를 실행하지 않고 테스트를 진행한 것을 알 수 있습니다. 

 

 

toBeCalled

toBeCalled() 함수는 한번이라도 호출된 적이 있다면 테스트가 통과되는 함수이다. 

 

toBeCalledTime

toBeCalledTime(parameter) 함수는 함수가 해당 파라미터 만큼 호출되면 테스트가 통과하는 함수이다. 

 

toBeCalledWith

toBeCalledWith(parameter) 해당 파라미터를 가진 함수가 한번이라도 호출된 적이 있으면 통과하는 함수이다. 

 

lastCalledWith

lastCalledWith(parameter) 해당 파라미터를 가진 함수가 가장 마지막에 호출되었는지 체크해서 통과시키는 함수이다. 

 

const fn = jest.fn();

fn(10, 20);
fn();
fn(30, 40, 50);
fn(60, 70, 80);

test('한번 이라도 호출?', () => {
    expect(fn).toBeCalled();
});

test('정확히 4번 호출?', () => {
    expect(fn).toBeCalledTimes(4);
});

test('정확히 4번 호출?', () => {
    expect(fn).toBeCalledTimes(3); // 테스트 통과 x
});

test("30, 40, 50가진 함수가 호출된적 있어", ()=>{
    expect(fn).toBeCalledWith(30, 40, 50);
});

test("30, 40, 50가진 함수가 호출된적 있어", ()=>{
    expect(fn).toBeCalledWith(30, 40); // 테스트 통과 x
});

test("마지막에 호출되는 함수가 60, 70, 80이니?", ()=>{
    expect(fn).lastCalledWith(60, 70, 80);
});

 

좋은 글입니다.

www.daleseo.com/jest-mock-modules/

 

[Jest] jest.mock() 모듈 모킹

Engineering Blog by Dale Seo

www.daleseo.com