본문 바로가기
Programming/Javascript

Jest로 Mock 생성하기

by peter paak 2021. 1. 27.
728x90

오늘은 Jest로 Mock을 생성해보도록 하겠습니다.

회사에서 Open Layer와 Cesium으로 2D/3D 지도 변환하는 모듈을 생성하면서 인터페이스에 대한 테스트를 작성하기로 했습니다.

Jest의 경우 평소에 React 웹 프로젝트를 할 경우 react test library로 사용하면서 익숙한 상태였지만, 모듈을 만들면서 정말 많은 dependency들이 엮인 프로젝트에서 사용해보는 것은 처음이었기에 Mock 생성하는데 많은 애를 먹었습니다. 특히 Cesium의 경우는 WebGL을 사용하여 canvas로 3D를 표현하는 코드가 함께 섞여있어 dependency를 그대로 가져와서 테스트하기가 힘들었습니다. 그래서 dependency를 가져와서 Mock 함수/객체를 생성하는 방향으로 개발했었습니다.

Jest로 Mock을 만드는 방식에 대해서 잘 이해가 많이 가지 았았는데 최대한 쉽게 설명해보려고 합니다.

소스코드는 github에서 확인하실 수 있습니다.

개요

한마디로 jest.mock("파일 위치")를 사용하면 됩니다. 간단한 예로 한번 살펴보겠습니다.
video.js

export default class Video {
    constructor() {}

    play(name) {
        console.log("play " + name);
    }
}

video.js

import Video from "./video";

export default class TV {
    constructor() {
        this.video = new Video();
    }

    play(video) {
        this.video.play(video);
    }
}

Youtube라는 클래스는 Video라는 dependency를 가지고 있습니다. 그리고 Video의 play라는 함수를 테스트 해보겠습니다.

youtube.test.js

import Video from './video'
import TV from './tv'

describe.skip("TV Test", () => {
    test("should play video", () => {
        const tv = new TV();
        console.log(tv);
    });
});

아직 테스트에 대한 검증을 하지않고 console의 결과만 보겠습니다.

예상했다시피 TV의 인스턴스가 생성되면 TV의 생성자에서 Video의 인스턴스도 함께 생성됩니다.

export default class TV {
    constructor() {
        this.video = new Video();
    }
}

하지만 TV 내부의 Video라는 인스턴스가 잘 생성이 되었는데 Video가 가진 메소드는 무엇인지, 메소드가 실패하지 않았는지 알 방법이 없습니다. 왜냐하면 TV라는 객체 내부에 일부러 숨겨놓은 객체를 밖으로 꺼내서 확인한다는 것은 객체지향의 은닉화에 위배되기 때문입니다. 이때 사용할 것이 바로 jest.mock()입니다. jest.mock()에 Video 클래스의 경로를 넣어서 jest.mock으로 감싸 생성된 가짜 객체를 TV에 넣어주게 됩니다.

import Video from "./video";
import TV from "./tv";

jest.mock("./video");

describe("TV Test", () => {
    test("should play video", () => {
        const tv = new TV();
        console.log(tv);
    });
});

결과를 보게되면 TV라는 인스턴스에 Video 인스턴스가 있고 그의 메소드를 가지고 있는 것을 볼 수 있습니다. video의 play라는 함수는 원래의 기능인 console.log(video)가 아닌 mockReturnValue 등인 jest.mock()이 가지는 함수로 감싸지게 됩니다. 즉, 우리가 마음대로 play라는 함수의 결과를 결정하고 가짜 video의 결과를 조절할 수 있게 됩니다.

그러면 실제 Video가 어떻게 출력되는지 보겠습니다.

describe("TV Test", () => {
    test("should play video", () => {
        const tv = new TV();
        console.log(Video);
    });
});

앞서 살펴본 play라는 함수처럼 Video라는 클래스도 똑같이 mockReturnValue 등의 메소드를 가지고 있습니다. 여기서 알 수 있는 것은 jest.mock()으로 감싸지 모든 mock 객체, 그 내부의 함수들은 모두 똑같은 메소드들을 가지고 우리가 컨트롤 할 수 있게 됩니다.

실제로는 다음과 같은 동작으로 mock 객체가 생성되게 됩니다.

즉, Tv라는 인스턴스가 생성되는 시점 이전에 jest.mock()을 통해 가짜 Video를 Tv 클래스에 주입하게 되는 것입니다.

다음 시간에는 내부에서 생성된 video의 인스턴스가 생성됬는지 검증하는 방법과 video의 play라는 함수가 어떤 인자로 실행되었고, 잘 시행되었는지 검증하는 방법에 대해서 알아 보도록 하겠습니다.

728x90