logo
Published on

[React Testing] 모킹

Authors
  • avatar

    jangth

외부 모듈(라이브러리)를 검증해야 할까? 대표적인 예로 react-router-dom 라이브러를 사용할 때 테스트 코드작 성 시 과연 react-router-dom에서 제공하는 API가 제대로 동작하는지 검증할 필요가 있을까?

react-router-dom라이브러리 자체적으로 이미 테스트가 완료되었기 때문에 굳이 검증할 필요가 없고 단순 API 호출을 잘하는지 인자를 제대로 전달 받는지 여부를 테스트하면된다.

모킹(Mocking)

실제 모듈﹒객체와 동일한 동작을 하도록 만든 모의 모듈﹒객체(Mock)로 실제를 대체하는 것

jest.mock()과 jest.fn

  • jest.mock()
    • 외부 모듈을 모킹할 때 사용
    • 모듈 전체를 모킹하여 모듈 내부의 함수나 속성들을 자유롭게 조작 가능
  • jest.fn()
    • 단순 함수 모킹
    • 함수의 호출, 횟수, 인자를 받는지, 반환 값 등을 확인할 수 있다.
const navigateFn = jest.fn()
jest.mock('useNavigate', async () => {
  const original = await jest.importActual('react-router-dom')
  return {
    ...original,
    useNavigate: () => navigateFn,
  }
})

it('', () => {
  //....
  expect(navigateFn).toHaveBeenNthCalledWith(1, '/')
})

jest.mock는 react-router-dom을 import하고 이를 가로채 모듈을 모킹한다. 그리고 콜백함수를 통해 세부적은 구현사항을 커스텀할 수 있다.

  • importAcutal : 실제 해당 모듈 api를 그대로 사용
  • useNavigate : 테스트하고자 하는 api이며 이를 navigateFn으로 모킹한다.
  • 단언(expect)으로 호출 횟수와 전달할 인자를 검증한다.

모킹 초기화

모킹을 했으면 초기화 하는 것이 매우 중요하다.

  • 다른 테스트에서는 특정 모듈에 대한 모킹이 필요 없다면?
  • 특정 테스트 모킹 작업이 다른 테스트에 영향을 준다면? 다른 테스트에 영향을 줄 수 있어 초기화 하지 않는다면 테스트의 신뢰도가 매우 떨어진다. 따라서 테스트 실행 한 뒤에는 명시적으로 모킹을 초기화 해야한다.

jest.setup.ts 파일에서 모킹 히스토리와 초기화를 글로벌로 설정하면된다.

// jest.setup.ts
import '@testing-library/jest-dom'

afterEach(() => {
  // 모킹된 객체의 호출 회수, 인자 등 모킹 함수의 기록을 초기화
  jest.clearAllMocks()
})

afterAll(() => {
  // 모킹 함수의 내부 구현을 모두 초기화
  jest.resetAllMocks()
})