Jest

유의진·2024년 11월 26일
0
post-thumbnail

Jest 란

Jest는 페이스북에서 만들어서 React와 더불어 많은 자바스크립트 개발자들로 부터 좋은 반응을 얻고 있는 테스팅 라이브러리다.

toBe vs toEqual

toBe는 참조값(주소값)을 비교하는 함수이다.
toEqual은 값? 을 비교하는 함수이다.

  • 객체를 비교할 때 객체는 각자의 메모리 주소를 가지고 있기 때문에 내용이 같더라도 참조값이 다르기 때문에 toBe는 다르다고 나온다.
  • toEqual은 실제 값을 비교하기 때문에 객체 내부의 값이 동일하다면 같다고 나온다.
    • toStrictEqual: undefined를 허용하지 않는다.
  • number, boolean, string에는 참조값이 정해져 있어서 차이가 없다.
  • 배열도 객체와 동일한듯?
describe('to be vs to equal', () => {
  test('test', () => {
    const a = [1];
    expect(a).toBe([1]); // false
  });

  test('test', () => {
    const a = [1];
    expect(a).toEqual([1]); // true
  });

  test('test', () => {
    expect([1]).toBe([1]); // false
  });
});
  • toBe 코드
    getJasmineRequireObj().toBe = function(j$) {
      /**
       * {@link expect} the actual value to be `===` to the expected value.
       * @function
       * @name matchers#toBe
       * @since 1.3.0
       * @param {Object} expected - The expected value to compare against.
       * @example
       * expect(thing).toBe(realThing);
       */
      function toBe(matchersUtil) {
        var tip = ' Tip: To check for deep equality, use .toEqual() instead of .toBe().';
    
        return {
          compare: function(actual, expected) {
            var result = {
              pass: actual === expected
            };
    
            if (typeof expected === 'object') {
              result.message = matchersUtil.buildFailureMessage('toBe', result.pass, actual, expected) + tip;
            }
    
            return result;
          }
        };
      }
    
      return toBe;
    };
  • toEqual 코드
    getJasmineRequireObj().toEqual = function(j$) {
      /**
       * {@link expect} the actual value to be equal to the expected, using deep equality comparison.
       * @function
       * @name matchers#toEqual
       * @since 1.3.0
       * @param {Object} expected - Expected value
       * @example
       * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
       */
      function toEqual(matchersUtil) {
        return {
          compare: function(actual, expected) {
            var result = {
                pass: false
              },
              diffBuilder = j$.DiffBuilder({prettyPrinter: matchersUtil.pp});
    
            result.pass = matchersUtil.equals(actual, expected, diffBuilder);
    
            // TODO: only set error message if test fails
            result.message = diffBuilder.getMessage();
    
            return result;
          }
        };
      }
    
      return toEqual;
    };
    

Jest로 Promise 테스트

1. Promise 객체로 받는 경우

test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});

→ return을 해야하는 이유: return을 사용해야 jest는 promiseresolve 될 때까지 기다리기 때문이다.

.resolves/.rejects 사용하면

test('the data is peanut butter', () => {
  return expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', () => {
  return expect(fetchData()).rejects.toMatch('error');
});

반드시 return을 해야한다.
→ return이 없으면 data를 fetch 하고 콜백을 실행하기 전에 테스트가 완료됨

2. async/await

test('the data is peanut butter', async () => {
  const data = await fetchData();
  expect(data).toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  try {
    await fetchData();
  } catch (error) {
    expect(error).toMatch('error');
  }
});
test('the data is peanut butter', async () => {
  await expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  await expect(fetchData()).rejects.toMatch('error');
});

올바른 promise는 reloves로 풀고 toBe로 비교한다.
에러 promise는 rejects로 받고 toMatch로 비교한다.
→ toMatch는 정규식 비교
→ toBe로 비교하면 안되나?
→ toThrow 쓸듯

toThrow 예시 코드

test("Test description", () => {
  const t = () => {
    throw new TypeError("UNKNOWN ERROR");
  };
  // 타입에러 객체 확인
  expect(t).toThrow(TypeError);
  // 에러 메시지 확인
  expect(t).toThrow("UNKNOWN ERROR");
});

// toThrow 사용
test("test", () => {
	expect(() => {
		throw new Error("ERROR")
	}).toThrow("ERROR")
})

Mock function

jest.jn()

mockReturnValue(value)

const mockFn = jest.fn()

mockFn() // undefined
mockFn(1) // undefined

mockFn.mockReturnValue(1)
mockFn() // 1

mockFn.mockReturnValue('a')
mockFn() // a

mockInplemetation(value)

  • 모킹 함수를 구현 (동작이 가능한)
const mockFn = jest.fn();

mockFn.mockImplementation((name) => `hi ${name}`);
console.log(mockFn('a')); // hi a

const mockFn = jest.fn((name) => `hi ${name}`) // 가능

mockResolvedValue(value) / mockRejectedValue(value)

  • 비동기 상황에서 resolve / reject 값을 받는다
test('resolve test', async () => {
  const mockFn = jest.fn().mockResolvedValue(1);

  expect(await mockFn()).toEqual(1);
});

test('reject test', async () => {
  const mockFn = jest.fn().mockRejectedValue(new Error('error'));

  expect(mockFn()).rejects.toThrow('error');
});

toBeCalledtoHaveBeenCalled랑 똑같음
toHaveBeenCalled: mock 함수가 호출 되었는지 확인
toHaveBeenCalledTimes: 함수가 몇번 호출 되었는지 확인
toHqveBeenCalledWith: 함수가 특정 인자(props)를 포함해서 호출이 되었는지 확인

jest.mock

jest.fn()과 비슷하지만 그룹을 한꺼번에 모킹 처리할 때 사용한다.

Spy function

jest.spyOn

헤당 함수의 호출 여부와 어떻게 호출 되었는지 확인한다.

  test('spyOn test', () => {
    const calculator = {
      add: (a, b) => a + b,
    };

    const spyFn = jest.spyOn(calculator, 'add');

    const result = calculator.add(1, 2);

    expect(spyFn).toHaveBeenCalled();
    expect(spyFn).toHaveBeenCalledTimes(1);
    expect(spyFn).toHaveBeenCalledWith(1, 2);
    expect(result).toBe(3);
  });

추가로 학습해야될 부분

Promise
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
Javascript 동작 원리
https://velog.io/@rnjsrntkd95/Call-Stack-Event-loop-Task-Queue

참고

toBe, toEqual
https://stackoverflow.com/questions/22413009/jasmine-javascript-testing-tobe-vs-toequal
jest promise
https://jestjs.io/docs/asynchronous#asyncawait
jest mock
https://inpa.tistory.com/entry/JEST-📚-모킹-mocking-jestfn-jestspyOn

profile
안녕하세요. 프론트엔드 개발 공부를 하고 있습니다.

0개의 댓글

관련 채용 정보