【React】テスト

Reactでのテストについてこちらの書籍にて学んだことをまとめています。

ReactではテストフレームワークにはJestというツールを使用します。

Jestとは

ReactのコンポーネントをNode上でテストするために使用されるツールのことです。

ESLintやPrettierと違い、コードをパースするだけでなく、実際にコードを実行してテストします。

Jestはcreate-react-appで作成したプロジェクトにはデフォルトで含まれています。

インストールと設定

create-react-appで作成したプロジェクトでない場合は、インストールと初期設定が必要になります。

インストール

$ npm i -D jest

設定

以下コマンドより、設定ファイルを自動生成します。

$ npx jest --init

いくつか質問に答えます。

・テスト環境はjsdom (browser-like)を選択

これにより、ブラウザ環境のシミュレーションが可能になります。

・coverage reportsはNoを選択

・instrument code for coverageはbabelを選択

・Automatically clear mock calls, instances and results before every test?はNoを選択

これにより、jest.config.jsが生成されます。

単一の関数のテスト

それでは、実際にテストを実行していきたいと思います。

テストサンプル関数用のファイルと、テスト用のファイルを、それぞれ、function.jsとfunction.test.jsという名前で作成します。

ファイル位置はsrcの直下とします。

受け取った数値を2倍にして返す関数を作ります。これがテスト対象のファイルです。

export function timesTwo(a) {
  return a * 2;
}

次にテストファイルを作ります。

import { timesTwo } from "./functions";

test("Multiplies by two", () => {
  expect(timesTwo(5)).toBe(10);
});

testは、Jestが提供するグローバル関数です。

このグローバル関数testには通常引数が3つあります。

第1引数:「テスト名」

第2引数:「テストのコードを含む関数」

第3引数:「テストが完了しなかった場合のタイムアウト」
指定しなかった場合、デフォルト値の2秒になります。

検証は、expect関数を使用します。

toBeというマッチャーを使用し、等しいかをテストしています。

これを以下コマンドで実行します。

$ npm test

すると、以下の結果が返ってきて、passedとなっているのでテストが通っていることが確認できました。

 PASS  src/App.test.js
 PASS  src/functions.test.js

Test Suites: 2 passed, 2 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        1.019 s

配列の値のテスト

先程は数値のテストをしましたが、テスト対象が配列の場合のテスト方法について見ていきます。

注文リストから合計を求める関数でテストを行います。

export function order(items) {
  const total = items.reduce((price, item) => price + item.price, 0);
  return {
    orderItems: items,
    total
  };
}

ここで使用しているreduceメソッドとは、以下の形で使用されるものです。

配列.reduce((累積値, 要素) => 返り値)

配列の合計を算出するのに使えるメソッドです。

引数itemsには3つのオブジェクトが入っており、その中のpriceプロパティの値を合計しています。

テスト用に3つのオブジェクトデータを作成します。

import { order } from "./functions";

const menuItems = [
  {
    id: "1",
    name: "natto",
    price: 100
  },
  {
    id: "2",
    name: "tamago",
    price: 200
  },
  {
    id: "3",
    name: "chicken",
    price: 300
  }
];

test("Purchase list", () => {
  const result = {
    orderItems: menuItems,
    total: 600
  };
  expect(order(menuItems)).toEqual(result);
});

オブジェクトの場合は、toBeでなく、toEqualを使用します。

複数の関連するtestをまとめるdescribe

複数の関連するtestをまとめるるためにはdescribe関数を使用します。

例えば、、

describe("spending", () => {
  test("Housing expenses", () => {
    ...
  });
  test("Food expenses", () => {
    ...
  })
})

このようにグループ化することで、テスト結果を見やすくすることができます。

コンポーネントのテスト

ReactのコンポーネントはNode.jsを使ってテストすることが可能です。

こちらで作成したStarコンポーネントを使って例を見ていきます。

import { FaStar } from "react-icons/fa";

export default function Star({ selected = false }) {
  return <FaStar color={selected ? "red" : "gray"} id="star" />;
}

Starコンポーネントのテストファイルを作成します。

import ReactDOM from "react-dom";
import Star from "./Star";

test("renders a star", () => {
  const div = document.createElement("div");
  ReactDOM.render(<Star />, div);
  expect(div.querySelector("svg")).toBeTruthy();
});

  1. div要素を作成
  2. ReactDOM.renderでdiv要素に対しStarコンポーネントを描画
  3. div要素の中にsvg要素が含まれているかをテスト

コンポーネントのテストは、このように行います。

イベントのテスト

以下で作成したCheckboxコンポーネントを使用して、イベントのテスト例を見ていきます。

import React, { useReducer } from "react";

export function Checkbox() {
  const [checked, setChecked] = useReducer((checked) => !checked, false);

  return (
    <>
      <label>
        {checked ? "checked" : "not checked"}
        <input type="checkbox" value={checked} onChange={setChecked} />
      </label>
    </>
  );
}

チェックボックスのクリックにより、checkedの値がfalse ⇔ trueと切り替わることの確認テストをします。

  1. getByLabelText()を使って、input要素を参照できるようにする
  2. ラベルの文字列がnot checkedとなっていることを、正規表現を使って検索
  3. fireEventを使って、クリックイベントを送信する
  4. それにより取得するプロパティcheckedの値がtrueであることをテスト
  5. クリックイベントと、checkboxの値反転テストをもう一度実施
    今度は値がfalseになっているはず。

コードがこちら

import { render, fireEvent } from "@testing-library/react";
import { Checkbox } from "./Checkbox";

test("Selecting the checkbox should change the value of checked to true", () => {
  const { getByLabelText } = render(<Checkbox />);
  const checkbox = getByLabelText(/not checked/);
  fireEvent.click(checkbox);
  expect(checkbox.checked).toEqual(true);
  fireEvent.click(checkbox);
  expect(checkbox.checked).toEqual(false);
});

テスト実施率測定 コードカバレッジ

全体のコードのうち、どれだけの行数がテストされたかを測定することができます。

それを%で表すことをコードカバレッジといいます。

Jestでコードカバレッジを利用するには以下コマンドを実行します。

$ npm test -- --coverage

これを実行すると、ルートディレクトリにcoverageフォルダが生成されます。

この中のcoverage/lcov-report/index.htmlをブラウザで開くことができ、以下の画面のようなレポートを表示することができます。

それぞれのコンポーネント名をクリックすると、コードを表示することができ、どこがテスト済みなのかも確認することができます。

以上、お読みいただきありがとうございました。

コメント