jest.clearAllMocks 대 jest.resetAllMocks 대 jest.restoreAllMocks 설명

이러한 clearAllMocks, resetAllMocks 및 restoreAllMocks가 실제로 수행하는 작업과 왜 필요한지에 대해 기억하고 혼동하기 어려웠다는 것을 알고 있습니다.

마음을 비울 수 있게 해주세요!

jest.clearAllMocks


mock.calls , mock.instances , mock.contextsmock.results 와 같은 모든 모의 사용 데이터를 지우지만 해당 구현은 지우지 않습니다.

모의 함수가 호출될 때마다 해당 사용 컨텍스트를 모의 함수 개체 자체에 유지합니다.

다음 예를 들어 보겠습니다. 난수를 얻기 위해 실제로 getRandomNumber를 호출하는 randomNumberGenerator()를 테스트할 것입니다. 따라서 이 경우에는 random.service 모듈을 조롱합니다.

// main.test.js
jest.mock('random.service')

const { randomNumberGenerator } = require('random.service')

const getRandomNumber => randomNumberGenerator()

it('should return a number', () => {
  randomNumberGenerator.mockReturnValue(7)
  const num = getRandomNumber()

  console.log(randomNumberGenerator.mock) // 👈 check this out!

  expect(num).toBe(7)
})

getRandomNumber 함수를 호출하면 그에 따라 모의 함수randomNumberGenerator도 호출됩니다. 그런 다음 console.log(randomNumberGenerator.mock) 다음과 같은 것을 볼 수 있습니다.

{
  calls: [ [] ],
  contexts: [
    <ref *1> {...}
  ],
  instances: [
    <ref *1> {...}
  ],
  invocationCallOrder: [ 1 ],
  results: [ { type: 'return', value: 2 } ],
  lastCall: []
}


컨텍스트는 호출 수를 예상하고 함수에 반환이 있는지 등과 같은 일부 어설션 목적에 유용합니다. 이는 또한 교차 테스트 사례 어설션을 위해 이러한 컨텍스트가 필요할 수 있는 특정 사용 사례에 유용할 수 있습니다.

그러나 이것도 지우지 않으면 문제가 발생할 수 있습니다. 아래 예

it('example 1', () => {
  randomNumberGenerator.mockReturnValue(7)
  const num = getRandomNumber()
  expect(randomNumberGenerator).toBeCalledTimes(1)
})

it('example 2', () => {
  randomNumberGenerator.mockReturnValue(8)
  const num = getRandomNumber()
  expect(randomNumberGenerator).toBeCalledTimes(1) // This will failed!! because it expect 2 times.
})


두 번째 예는 실패할 것이며 이는 mock.calls에 2개의 카운트가 있기 때문입니다. 이를 수정하려면 jest.clearAllMocks 또는 afterEach와 같이 jest global에서 beforeEach를 사용해야 합니다.

beforeEach(() => {
  jest.clearAllMocks()
})


이것은 다음 테스트 사례가 시작되기 전에 모든 모의 사용 데이터를 지우도록 jest에게 지시합니다.

jest.resetAllMocks


clearAllMocks() 의 상위 집합이며 새로운 jest.fn() 로 모의 함수 구현을 재설정합니다.

기본적으로 구현되지 않은 모든 모의 함수는 항상 undefined 를 반환합니다. 그리고 구현이 추가되면 모의 함수 개체에 구현이 유지됩니다.

다음 코드는 모든 것을 설명합니다.

it('example 1', () => {
  randomNumberGenerator.mockReturnValue(7)
  const num = getRandomNumber()
  expect(num).toBe(7)
})

it('example 2', () => {

  // we didn't mock `randomNumberGenerator` in this test but this will return 7 because the last test case is added implementation.
  console.log(randomNumberGenerator())

  const num = getRandomNumber()
  expect(num).toBe(7)
})


모의 함수를 재사용할 필요가 있을 때 유용합니다. 따라서 모든 테스트 사례에서 다시 작성할 필요가 없습니다.

모든 테스트 케이스가 신선하고 새롭고 독립적인 것을 원한다면. 각 테스트 사례가 시작되기 전에 사용해야 합니다. 그것은 각 테스트 케이스에 대해 부작용이 없고 걱정을 덜 수 있음을 보장할 수 있습니다.

jest.restoreAllMocks



모든 모의를 원래 구현으로 복원하면 jest.spyOn 로 생성된 모의에 대해서만 작동합니다.

어떤 이유로 모듈을 특정 기능으로 부분적으로 모의해야 합니다. 전형적인 예는 다음 예와 같이 관련된 날짜 시간을 테스트하는 것입니다.

it('should be my birthday', () => {
  jest.spyOn(Date, 'now').mockReturnValue('2022-08-31T15:23:19.576Z')
  const result = isTodayMyBirthday()
  expect(result).toBe(true)
})


이것은 잘 작동하지만 spyOn은 일종의 모듈 개체를 변경하는 것과 같기 때문에 위험하며 모든 모의 복원을 잊은 경우 후속 테스트는 Date.now()의 모의 버전을 사용하고 있으며 이것은 실제로 명확하지 않고 디버그하기 어렵습니다.

이전 솔루션과 마찬가지로 모든 다음 테스트 케이스 전에 지우십시오.

beforeEach(() => {
  jest.restoreAllMocks()
})


테스트 케이스에 spyOn이 표시될 때 주의하십시오. 테스트 실패의 원인이 될 수 있습니다.

결론



보시다시피 모의 API 동작은 항상 상태를 유지하고 명시적으로 지우고/재설정/복원해야 합니다. 테스트 사례가 항상 새롭고 부작용이 없는 상태로 시작하려면 이 작업을 수행하는 것이 더 좋습니다. jest 구성에서 할 수 있습니다.

// jest.config.js

const config = {
  clearMocks: true,
  resetMocks: true,
  restoreMocks: true
}


이것이 당신이 더 나은 이해를 하는 데 도움이 되기를 바랍니다. 좋아요, 유니콘 또는 도움이 된다면 저장하세요! 고맙습니다.

좋은 웹페이지 즐겨찾기