Jest 공식문서 읽으며 메모 🪶

9rganizedChaos·2023년 8월 2일
0

Matchers

toBe & toEqual

  • toBe는 값과 타입이 동일한지 모두 검사, 객체나 배열의 참조값까지 비교, toEqual은 값만을 비교하며, 객체나 배열 내부의 값이 동일한지 검사
  • toEqual recursively checks every field of an object or array.
test('object assignment', () => {
  const data = {one: 1};
  data['two'] = 2;
  expect(data).toEqual({one: 1, two: 2});
});

Truthiness

아래와 같은 matcher들이 존재한다.
toBeNull
toBeUndefined
toBeDefined
toBeTruthy
toBeFalsy

숫자비교

아래와 같은 matcher들이 존재한다.
toBeGreaterThan
toBeGreaterThanOrEqual
toBeLessThan
toBeLessThanOrEqual

  • 소수점 계산에서 오차가 발생할 수 있으므로, toBeCloseTo를 활용

이터러블

객체나 set과 같은 이터러블에 대하여 toContain matcher를 활용할 수 있다.

예외 처리

특정 함수가 에러를 반환하는지 아닌지를 테스트하기 위해서는 toThrow를 활용한다.
toThrow의 인자로 에러를 전달할 수도, 에러 메시지를 전달할 수도 있다.

이외의 수많은 Matcher는 여기서 확인할 수 있다.

비동기 코드 테스트하기

Promises

  • 프로미스를 반환하는 함수의 경우, then을 활용하고 내부에서 expect문을 작성한다.
  • 이 때, promise가 reject되면 test는 실패하게 된다.
test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});

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 (e) {
    expect(e).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');
});

expect.assertions(n)

비동기 코드를 테스트할 때는 assetions를 써주는 게 좋다.
비동기로 테스트를 진행할 때에는 어떤 expect문이 먼저 실행될지, 그 순서를 보장받을 수 없으므로, test에게 몇개의 expect문이 포함될지를 미리 알려주는 절차라고 이해하면 쉽다.

test('doAsync calls both callbacks', () => {
  expect.assertions(2);
  function callback1(data) {
    expect(data).toBeTruthy();
  }
  function callback2(data) {
    expect(data).toBeTruthy();
  }

  doAsync(callback1, callback2);
});

Setup과 Teardown

  • beforeEach
  • afterEach
  • beforeAll
  • afterAll

beforeEach and afterEach can handle asynchronous code in the same ways that tests can handle asynchronous code - they can either take a done parameter or return a promise. For example, if initializeCityDatabase() returned a promise that resolved when the database was initialized, we would want to return that promise:

Scoping

Top-level에 있는 beforeEach는 특정 describe 스코프 안에 있는 beforeEach보다 앞서 실행된다.

beforeAll(() => console.log('1 - beforeAll'));
afterAll(() => console.log('1 - afterAll'));
beforeEach(() => console.log('1 - beforeEach'));
afterEach(() => console.log('1 - afterEach'));

test('', () => console.log('1 - test'));

describe('Scoped / Nested block', () => {
  beforeAll(() => console.log('2 - beforeAll'));
  afterAll(() => console.log('2 - afterAll'));
  beforeEach(() => console.log('2 - beforeEach'));
  afterEach(() => console.log('2 - afterEach'));

  test('', () => console.log('2 - test'));
});

// 1 - beforeAll
// 1 - beforeEach
// 1 - test
// 1 - afterEach
// 2 - beforeAll
// 1 - beforeEach
// 2 - beforeEach
// 2 - test
// 2 - afterEach
// 1 - afterEach
// 2 - afterAll
// 1 - afterAll

테스트 실행 순서

  • Jest는 테스트 파일 내의 모든 describe 핸들러를 실행한 후 실제 테스트를 실행한다.
  • describe 블록 내부가 아닌 before*after* 핸들러 내에서 설정 및 해체 작업을 수행하는 것이 더 좋은 이유 중 하나
  • before*after* 는 작성된 순서대로 실행된다.

Mock 함수

Jest Mock 함수 이용하기

  • const mockCallback = jest.fn(x => 42 + x); 라고 할 때
  • mockCallback.mock.calls: 목 함수가 호출될 때 전달인자를 담은 정보
  • mockCallback.mock.results: 목 함수가 반환한 결과를 담은 정보

.mock 속성

  • .mock 속성은 각 콜의 this를 추적한다.
const myMock1 = jest.fn();
const a = new myMock1();
console.log(myMock1.mock.instances);
// > [ <a> ]

const myMock2 = jest.fn();
const b = {};
const bound = myMock2.bind(b);
bound();
console.log(myMock2.mock.contexts);
// > [ <b> ]

// The function was called with a certain `this` context: the `element` object.
expect(someMockFunction.mock.contexts[0]).toBe(element);

// This function was instantiated exactly twice
expect(someMockFunction.mock.instances.length).toBe(2);

// The object returned by the first instantiation of this function
// had a `name` property whose value was set to 'test'
expect(someMockFunction.mock.instances[0].name).toBe('test');

// The first argument of the last call to the function was 'test'
expect(someMockFunction.mock.lastCall[0]).toBe('test');

Return Value 모킹하기

  • .mockReturnValueOnce

모듈 모킹하기

  • mockResolvedValue
import axios from 'axios';
import Users from './users';

jest.mock('axios');

test('should fetch users', () => {
  const users = [{name: 'Bob'}];
  const resp = {data: users};
  axios.get.mockResolvedValue(resp);

  // or you could use the following depending on your use case:
  // axios.get.mockImplementation(() => Promise.resolve(resp))

  return Users.all().then(data => expect(data).toEqual(users));
});

부분 모킹하기

.requireActual

jest.mock('../foo-bar-baz', () => {
  const originalModule = jest.requireActual('../foo-bar-baz');

  //Mock the default export and named export 'foo'
  return {
    __esModule: true,
    ...originalModule,
    default: jest.fn(() => 'mocked baz'),
    foo: 'mocked foo',
  };
});

내부 구현 자체를 모킹하기

  • mockImplementation
  • 물론mockImplementationOnce도 존재
jest.mock('../foo'); // this happens automatically with automocking
const foo = require('../foo');

// foo is a mock function
foo.mockImplementation(() => 42);
foo();
// > 42
  • .mockReturnThis도 존재. this를 return하는 내부 구현을 모킹하는 함수

함수 네임 모킹

  • 디버깅 시 편리하게 활용 가능
  const mockAdd = jest.fn().mockName('바보');
  jest.mock('./math', () => ({
    add: mockAdd
  }));

  test('add function', () => {
    mockAdd.mockReturnValue(10);
    const result = math.add(3, 5);
    expect(mockAdd).toHaveBeenCalledWith(3, 5);
    expect(result).toBe(10);
  });

Custom matchers for mock fn

// The mock function was called at least once
expect(mockFunc).toHaveBeenCalled();

// The mock function was called at least once with the specified args
expect(mockFunc).toHaveBeenCalledWith(arg1, arg2);

// The last call to the mock function was called with the specified args
expect(mockFunc).toHaveBeenLastCalledWith(arg1, arg2);

// All calls and the name of the mock is written as a snapshot
expect(mockFunc).toMatchSnapshot();
profile
부정확한 정보나 잘못된 정보는 댓글로 알려주시면 빠르게 수정토록 하겠습니다, 감사합니다!

0개의 댓글