본문 바로가기

FrontEnd

리액트 테스트 : 라이브러리 없이 Counter 테스트하기

반응형
소프트웨어를 사용하는 것처럼 테스트하라- @kentcdodds

자바스크립트 테스트는 무엇일까요?

어떤 상태를 설정하고, 어떤 동작을 수행하고, 새로운 상태에 대한 주장을 하는 코드일 뿐입니다.

상태 > 동작 > 새로운 상태(assertion)

 

아래의 간단한 카운터 컴포넌트를 위의 원칙에 따라 테스트해 봅시다.

 

테스트 작성 시, 두 사용자를 고려합니다.

  • 최종 사용자 : 사용자들이 내 코드와 인터랙션 하는 방법(버튼 클릭 등)
  • 개발자 사용자 : 개발자들이 내 코드를 사용하는 방법 (렌더링, 함수 호출 등)
    • 테스트 사용자(The Test User)는 고려 대상이 아닙니다!

리액트 컴포넌트 관점에서

  • 개발자 사용자는 react-dom의 createRoot API(React Native와 유사한 개념)를 사용하여
    • 컴포넌트를 렌더링하고
    • props를 전달하거나
    • 컨텍스트 공급자에 래핑합니다.
  • 최종 사용자는
    • 버튼을 클릭하고
    • 출력을 기대(assert)합니다

이 두 가지가 우리 테스트가 해야 할 일입니다.

1. Counter Component 그리기

test('counter increments and decrements when the buttons are clicked', () => {
  const div = document.createElement('div')
  document.body.append(div)
  ReactDOM.render(<Counter />, div)
})

아래와 같이 그려짐


2. Counter  Component 초기값 테스트

test('counter increments and decrements when the buttons are clicked', () => {
  const div = document.createElement('div')
  document.body.append(div)

  ReactDOM.render(<Counter />, div)
  const [decrement, increment] = div.querySelectorAll('button')
  const message = div.firstChild.querySelector('div')
  // 한줄 추가.
  expect(message.textContent).toBe('Current count: 0')
}

3. 증가, 감소 기능 테스트

test('counter increments and decrements when the buttons are clicked', () => {
  const div = document.createElement('div')
  document.body.append(div)

  ReactDOM.render(<Counter />, div)
  const [decrement, increment] = div.querySelectorAll('button')
  const message = div.firstChild.querySelector('div')

  expect(message.textContent).toBe('Current count: 0')
  increment.click()
  expect(message.textContent).toBe('Current count: 1')
  decrement.click()
  expect(message.textContent).toBe('Current count: 0')
})

4. 테스트 환경 초기화하기

jestDOM은 전체가 공유합니다.

따라서 개별 test suite가 정상 작동하려면, 매 테스트 마다 독립성을 보장해줘야 합니다.

아래와 같이 매 테스트 전에 document.body를 초기화해줍니다.

beforeEach(() => {
  document.body.innerHTML = ''
})
테스트가 서로 완전히 격리되어 실행될 수 있도록, 각 테스트 사이에 환경 정리의 중요성을 잊지 말자.

5. dispatchEvent 사용

위의 테스트에서는 dom을 클릭하고 있습니다.

이는 사용자가 브라우저에서 해당 dom을 사용하는 방법과 동일합니다.

하지만, 특정 이벤트는 dom에 대해 직접 호출하기 어려울 수 있습니다. (mouseover)

 

이를 위해 Event객체를 만들어 dispatch 합니다.

리액트는 이벤트 위임을 사용하기 때문에, bubbles : true 플래그를 사용합니다.

또한 해당 이벤트는 취소 가능합니다.

버튼 : 0 은 왼쪽 버튼을 의미합니다.

new MouseEvent('click', {
  bubbles: true,
  cancelable: true,
  button: 0,
})

 

추가로 공부하기

assertion에 대해 더 알아보기

Expect · Jest (jestjs.io)

 

Expect · Jest

When you're writing tests, you often need to check that values meet certain conditions. expect gives you access to a number of "matchers" that let you validate different things.

jestjs.io

세부 구현을 테스트하지 말라!

Avoid the Test User (kentcdodds.com)

 

Avoid the Test User

How your UI code has only two users, but the wrong tests can add a third

kentcdodds.com

 

반응형