📌

EnzymeとReact Testing Libraryの違いを調べてみた

2024/07/12に公開

この記事は何?

  • 過去に少しだけEnzymeを触ったことがあり、最近Reactを触るようになったため、公式から推奨されているテストライブラリについて調べた

Enzymeとは?

  • Airbnb によって開発された
    • React v16 までしかサポートしていない
  • コンポーネントの内部構造や状態にフォーカスしており、コンポーネントのメソッドや状態を直接テストすることが可能
    • コンポーネント内のメソッドを単体でテストすることができる
    • Vue.jsのテストライブラリ(Vue Test Utils)に近い

React Testing Library

  • Kent C. Dodds(Testing Trophyの考案者)によって開発された
  • ユーザー視点でテストすることを重視しており、コンポーネントを操作して表示される内容をテストする
    • E2Eに近いイメージ
    • コンポーネント内にアクセスすることができない

コードで差を見てみる

※EnzymeとReact Testing Libraryを同時に使うため、React v16を使っています。

import React, { Component } from "react"
import { render, screen } from "@testing-library/react"
import { userEvent } from "@testing-library/user-event"
import "@testing-library/jest-dom"
import Enzyme, { shallow } from "enzyme"
import Adapter from "enzyme-adapter-react-16"

class Button extends Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0
    }
  }

  handleClick = () => {
    this.setState({ count: this.state.count + 1 })
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick}>click</button>
        <p>{ this.state.count }回クリックされました</p>
      </div>
    )
  }
}



Enzyme.configure({ adapter: new Adapter() })
describe('Enzymeを使った場合のテスト', () => {
  test('ボタンが押下されるとカウントが増えること', () => {
    const wrapper = shallow(<Button />)

    // Enzymeの場合 CSSセレクタ等に依存する
    expect(wrapper.find('p').text()).toBe('0回クリックされました')
    wrapper.find('button').simulate('click')
    expect(wrapper.find('p').text()).toBe('1回クリックされました')
  })

  test('コンポーネントのインスタンスにアクセスできることの確認', () => {
    const wrapper = shallow(<Button />)

    expect(wrapper.find('p').text()).toBe('0回クリックされました')
    wrapper.instance().handleClick()
    expect(wrapper.find('p').text()).toBe('1回クリックされました')
  })
})

describe('React Testing Libraryを使った場合のテスト', () => {
  test('ボタンが押下されるとカウントが増えること', async () => {
    render(<Button />)

    // React Testing Libraryの場合 ユーザー視点でテストできる
    expect(screen.getByText('0回クリックされました')).toBeInTheDocument()
    await userEvent.click(screen.getByText('click'))
    expect(screen.getByText('1回クリックされました')).toBeInTheDocument()
  })

  test.skip('コンポーネントのインスタンスにアクセスできない')
})

感想

  • CSSセレクタ等に依存しないテストコードを書けるのは嬉しい
    • CSSセレクタに依存すると、classの付け替え等簡単な変更でテストが落ちるようになる
  • テスタブルなコードになっていないとReact Testing Libraryは使いにくそうに感じた
    • テストファーストやTDDで解決できそう
    • 先にユーザー視点でCSSセレクタ等に依存しないテストコードを書くことで、自然にテスタブルなプロダクションコードが書けそう

Discussion