ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Jest - Jest Object1 (jest.spyOn( ))
    FrameWork/Jest 2023. 3. 10. 15:43

    Jest Object

    jest.spyOn( )

    mocking에는 스파이(spy)라는 개념이 있다. 테스트를 작성할 때, 어떤 객에에 속한 함수의 구현을 가짜로 대체하지 않고, 해당 함수의 호출 여부와 어떻게 호출 되었는지만 알아내야 할 때가 있다. 이럴 때, Jest에서 제공하는 jest.spyOn(object,methodName)함수를 사용하면 된다.

     

    실제 구현 함수1

    obj.js

    const calculator = {
      add: (a, b) => a + b,
    };
    
    module.exports = calculator;

     

    obj.test.js

    const calculator = require("../../lib/obj");
    
    describe("Jest Object jest.spyOn() ", () => {
      test("spying", () => {
        const spyFn = jest.spyOn(calculator, "add");
    
        const result = calculator.add(2, 3);
    
        expect(spyFn).toBeCalledTimes(1);
        expect(spyFn).toBeCalledWith(2, 3);
        expect(result).toBe(5);
      });
    });

     위 코드를 보면 jest.spyOn( )함수를 이용해서 calculator객체의 add라는 함수에 스파이를 붙였다. 따라서 sypFn은 calculator 객체에 add메서드에 대한 호출횟수호출 시 들어간 인자 값을 알 수있다. 하지만 add메서드를 가짜 함수로 대체한 것은 아니기 때문에 결과 값은 원래 구현대로 2와 3의 합인 5가 되는 것을 확인할 수 있다.

     


    실제 구현 함수2

    userService.js

    const axios = require("axios");
    const API_ENDPOINT = "https://jsonplaceholder.typicode.com";
    
    exports.findOne = function findOne(id) {
      return axios
        .get(`${API_ENDPOINT}/users/${id}`)
        .then((response) => response.data);
    };

     

    user4.test.js

    const userService = require("../../service/userService");
    
    test("FindOne returns a user", async () => {
      const user = await userService.findOne(1);
      expect(user).toHaveProperty("id", 1);
      expect(user).toHaveProperty("name", "Leanne Graham");
    });

    우선 mocking 없이 findOne()의 결과 값에 대한 단순한 테스트를 작성한다.

     

    외부 모듈에 jest.spyOn( )사용해서 특정 메서드 spy하기 🧐

    test("findOn ftches data from the API endpoint", async () => {
      const spyGet = jest.spyOn(axios, "get");
      await userService.findOne(1);
      expect(spyGet).toBeCalledTime(1);
      expect(spyGet).toBeCalledWith(`https://jsonplaceholder.typicode.com/user/1`);
    });

    findOne()함수가 외부 API연동을 통해서 사용자 정보를 조회하는지 테스트 하려면 jest.spyOn()을 활용해서 axios의 get메서드를 spy하므로써 해당 메서드가  몇번 불러 와지고, 어떤 인자와 함께 불려지는지 확인하는 matcher를 사용해서 확인 할수 있다.

     

    하지만 위 코드의 테스트는 API서버가 다운된 상황이거나 Network가 단절된 환경에서 실행하면 오류가 발생하고 코드 이외의 이유로인해 테스트가 실패하게 된다. 따라서 위 두개의 테스트 함수는 "테스트 deterministic 해야한다.(언제 실행되는 항상 같은 결과를 내야한다.)"라는 원칙에 위배된다. unit 테스트가 단독으로 고립되어 있지 않고, 외부 환경에 의존적이기 때문이다.

     

    *deterministic : 결정론적 시스템, 결정론적 알고리즘을 의미 한다.

     

    이 문제를 해결하려면, axios 객제의 get 메서드가 항상 같은 결과를 반환하도록 mocking해야 한다. 

     

    Return 결과 mocking

    test("findOne returns what axios get returns", async () => {
      axios.get = jest
        .fn()
        .mockResolvedValue({ data: { id: 1, name: "surge100" } });
    
      const user = await userService.findOne(1);
      expect(user).toHaveProperty("id", 1);
      expect(user).toHaveProperty("name", "surge100");
    });

    앞서 언급한 문제를 해결하려면, axios객체의 get 메서드가 항상 동일한 결과를 반환하도록 mocking해야한다. 즉, 위 코드와 같이 axios.get()를 어떤 고정된 결과 값을 return하는 가짜함수로 대체해주면된다.

     

     

    출처 - https://www.daleseo.com/jest-fn-spy-on/

    댓글

Designed by Tistory.