본문 바로가기

FrontEnd

리액트 테스트 : 폼(Form) 테스트

반응형

TLDR:

  • mocking을 이용하여 software가 어떻게 사용되는지(how)를 명시적으로 테스트 할 수 있습니다. > jest.fn
    • 테스트 케이스 작성 시에는 소프트웨어가 사용되는 how에 집중하는게 좋습니다.
  • faker 라이브러리를 사용하여 매번 가짜 데이터를 만들 수 있습니다.
  • 테스트 객체를 쉽게 만들기 위해 오브젝트 팩터리 함수를 사용합니다.

 

 

사용자는 Form과 상호 작용하는 데 많은 시간을 할애하며 Form은 응용 프로그램에서 가장 중요한 부분입니다
(예: 전자 상거래 앱의 "체크아웃" Form 또는 대부분의 앱의 "로그인" Form).
사용자가 Form에서 입력을 찾고, 정보를 입력하고, Form을 제출할 때 제출된 데이터가 올바른지 확인할 수 있는지를 검증합니다.

로그인 폼 검증

테스트할 컴포넌트는 다음과 같습니다.

function Login({onSubmit}) {
  function handleSubmit(event) {
    event.preventDefault()
    const {username, password} = event.target.elements

    onSubmit({
      username: username.value,
      password: password.value,
    })
  }
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor="username-field">Username</label>
        <input id="username-field" name="username" type="text" />
      </div>
      <div>
        <label htmlFor="password-field">Password</label>
        <input id="password-field" name="password" type="password" />
      </div>
      <div>
        <button type="submit">Submit</button>
      </div>
    </form>
  )
}

export default Login

브라우저의 접근성 탭과, 테스팅 플라이그라운드를 활용하여 더 나은 품질의 테스트를 작성해 봅시다.

Accebility 탭 보기

테스팅 플레이그라운드 확장 프로그램

 

Testing Playground

Simple and complete DOM testing playground that encourage good testing practices.

chrome.google.com

chrome extension : Testing Playground

input type="password"에는 보안을 위해 암시적 Role이 없습니다.

통일성을 위해 username도 동일한 방법으로 쿼리합시다.

test('submitting the form calls onSubmit with username and password', () => {
  let submittedData
  const handleSubmit = data => (submittedData = data)
  render(<Login onSubmit={handleSubmit} />)
  const username = 'chucknorris'
  const password = 'i need no password'

  userEvent.type(screen.getByLabelText(/username/i), username)
  userEvent.type(screen.getByLabelText(/password/i), password)
  userEvent.click(screen.getByRole('button', {name: /submit/i}))

  expect(submittedData).toEqual({
    username,
    password,
  })
})

jest.fn()이용한 mocking

mocking을 이용하여 software가 어떻게 사용되는지(how)를 명시적으로 테스트 할 수 있습니다.

객체지향 설계, API 설계 시 how를 캡슐화 하는것은 중요하지만,

테스트 케이스 작성 시에는 소프트웨어가 사용되는 how에 집중하는게 좋습니다.

 

toHaveBeenCalledWith로 해당 파라미터로 호출되었는지,

toHaveBeenCalledTimes으로 단 한번만 호출되었는지 검증합니다.

test('submitting the form calls onSubmit with username and password', () => {
  const handleSubmit = jest.fn()
  render(<Login onSubmit={handleSubmit} />)
  const username = 'chucknorris'
  const password = 'i need no password'

  userEvent.type(screen.getByLabelText(/username/i), username)
  userEvent.type(screen.getByLabelText(/password/i), password)
  userEvent.click(screen.getByRole('button', {name: /submit/i}))

  expect(handleSubmit).toHaveBeenCalledWith({
    username,
    password,
  })
  expect(handleSubmit).toHaveBeenCalledTimes(1)
})

테스트 데이터 만들기

테스트에 사용되는 가짜 데이터가 어떤 값인지는 의미가 없습니다.

 

const username = getRandomUsername()
const password = getRandomPassword()

 

faker 라이브러리를 사용하여 매번 가짜 데이터를 만들 수 있습니다.

const {username, password} = buildLoginForm()

import * as React from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import faker from 'faker'
import Login from '../../components/login'

function buildLoginForm() {
  return {
    username: faker.internet.userName(),
    password: faker.internet.password(),
  }
}

test('submitting the form calls onSubmit with username and password', () => {
  const handleSubmit = jest.fn()
  render(<Login onSubmit={handleSubmit} />)
  const {username, password} = buildLoginForm()

  userEvent.type(screen.getByLabelText(/username/i), username)
  userEvent.type(screen.getByLabelText(/password/i), password)
  userEvent.click(screen.getByRole('button', {name: /submit/i}))

  expect(handleSubmit).toHaveBeenCalledWith({
    username,
    password,
  })
  expect(handleSubmit).toHaveBeenCalledTimes(1)
})

오버라이딩 허용하기

때때로 특정 값이 중요한 역할을 해야할 때가 있습니다. (ex root 사용자)

아래와 같이 오브젝트 팩토리를 사용합니다.

function buildLoginForm(overrides) {
  return {
    username: faker.internet.userName(),
    password: faker.internet.password(),
    ...overrides,
  }
}

테스트 데이터 봇

오브젝트 팩토리 함수를 만드는 것이 복잡할 수 있습니다.

위의 오버라이딩 기능을 제공하면서, 가짜데이터를 만드는 유틸리티 기능을 동시에 제공하는 라이브러리 입니다.

주의! : 최신 2.0.0 버전은 faker 기능을 걷어낸 것 같습니다. 1.4.0 버전을 사용합니다.

@jackfranklin/test-data-bot - npm (npmjs.com)

 

@jackfranklin/test-data-bot

Generate test data for your tests easily.

www.npmjs.com

import {build, fake} from '@jackfranklin/test-data-bot'
const buildLoginForm = build({
  fields: {
    username: fake(f => f.internet.userName()),
    password: fake(f => f.internet.password()),
  },
})

정리

  • 폼에서는 입력 데이터 검증이 중요하다.
  • 입력 데이터를 의미있게 생성 및 표현하는 것이 중요하다.
  • submit시 액션 테스트도 중요하다.
반응형