Reactアプリケーションの自動テスト入門

アプリケーション開発

当記事では、Reactアプリケーションのテスト方法とそれを自動化する方法を紹介します。

Z-A-K-I
Z-A-K-I

バックエンドの自動テスト経験はあるけど、フロントエンドアプリケーションは未経験。

という方におすすめです。

この記事では、以下のことを紹介してます。

  • フロントエンドアプリケーションの自動化について
  • JestとTestingLibraryの違い
  • テストプログラムの具体的な作成ステップ

テストには、単体テストや結合テスト、システムテストなど色々なテストがありますが、当記事では単体テストにの自動化について記載してます。

Reactを利用して、自動化の方法を手順を追ってご紹介します。当記事を読むことで、フロントエンドアプリケーションの自動テストについての基礎知識とテスト方法を知ることができます。

フロントエンドアプリケーションの自動化

フロントエンドアプリケーションの自動テストにはテスティングフレームワークが必要となります。

テスティングフレームワークとは、テストの実施や管理を支援する機能のパッケージです。テスティングフレームワークを利用することで、テストの実行や結果の収集や分析などが行えるようになります。

テスティングフレームワークは、各言語に定番のライブラリがあり、javaならjunit、.NETであれば、MSTestやxUnitなどがそれにあたります。フロントエンドアプリケーションでは「Jest」というテスティングフレームワークが定番です。

本記事ではJestを使った自動テストについて紹介していきます。

Jestと混同しがちな「TestingLibrary」

フロントエンドの自動テストをインターネットで検索すると、「Jest」のほか、「TestingLibrary」というものもヒットします。

まずは、TestingLibraryとJestの違いについて説明します。結論から延べるとJestとは言葉の違いだけ、という理解でよいです。「Jestを使う」は、「JestとTestingLibraryを使う」という意味となります。

二つの違いについて説明します。

Jestとは

JestはJavaScriptの自動テストを実行するための環境で、JavaScriptのテスティングフレームワークです。

本記事では、Reactで作成したプログラムをテスト対象としてますが、Reactに限らずVue.jsやjqueryで作成されたプログラムに対しても利用する事ができます。

TestingLibraryとは

Jestで作成されたテストコードで利用するテスト用のライブラリです。

テスト対象のDOMを取得したり、操作したりするためのライブラリです。JestとTestingLibraryの両方を導入する事でjavaScriptの自動テストが可能となります。

Jestはテストを実行するための実行環境、TestingLibraryはテストするためのDOMを取得するためのライブラリとなります。

JestとTestingLibraryの導入方法

Reactの場合、「create-react-app」コマンドを利用してReactプロジェクトを作成した場合は、Jest、TestingLibraryも一緒にインストールされます。そのため、個別の対応は不要です。

それ以外でプロジェクトを作成した場合は、別途導入が必要となります。

npmの場合は、以下コマンドで個別インストールができます。

npm install --save-dev jest

Jestで実施するテスト内容について

テストは、工程によってどのレベルの品質を担保するかが異なります。一般的な品質担保の定義は決まってますが、開発プロジェクトによって変わることもあります。そのため、開発プロジェクトごとにテスト内容が異なることがあるため、一概にこれが正解だとは名言できませんが、私の考えについて記載します。

フロントエンドのテスト手順

フロントエンドのテストプログラムは、以下の順番でテストプログラムを書きます。

  • レンダー準備
  • コンポーネントのレンダー
  • コンポーネントのイベントを実行
  • 結果の検証

それぞれについて記載します。

レンダー準備

テストするためには、テスト対象コンポーネントのレンダーが必要です。ここではコンポーネントをレンダーするための準備を行います。

このレンダーの準備とは、コンポーネントに受け渡すpropsを定義することです。コンポーネントは親コンポーネントからpropsを受け取り、そのpropsを使って処理を行います。レンダー準備では、そのpropsを疑似的に定義します。なお、propsを受け取らないコンポーネントの場合は、propsの擬似的な定義は不要です。

// 例えば以下のようなコンポーネントをテストする場合、propsである「value」と「setValue」を渡す必要がある。
<Test value={value} setValue={setValue}>
import {fireEvent, render, screen} from "@testing-library\react"
import Test from "./Test";

test("jestのテストケース1"){
    // テストメソッドの中で上の属性を定義してテスト対象コンポーネントに渡す。。
    const [value. setValue] = useState("");
    ・・・省略・・・
}

コンポーネントのレンダー

テスト対象のコンポーネントをレンダリングします。レンダー準備と合わせて以下のコードを書きます。

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

test("jestのテストケース1"){
    // テストメソッドの中で上の属性を定義してテスト対象コンポーネントに渡す。
    const [value. setValue]  useState("");
    // テスト対象コンポーネントのレンダー
    render(<Test value={value} setValue={setValue}>);
    ・・・省略・・・
}

コンポーネントのイベントを実行

コンポーネントのレンダーが完了したら、コンポーネント内のイベントを実行します。

ここでは例として、「Test」コンポーネントを利用します。

「Test」コンポーネントは、検索条件を入力して検索ボタンをクリックすることで親コンポーネントから渡されたsetValue関数を呼び出すコンポーネントと仮定します。

この場合、Testコンポーネント内の「検索ボタンをクリックする」というイベントを実行する必要があります。

検索ボタンをクリックするためには、Testコンポーネントから検索ボタンの要素を取得し、取得した要素に対してイベントを発火させる手順が必要となります。

ここまでのコードと合わせて以下のようなコードとなります。

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

test("jestのテストケース1"){
    // テストメソッドの中で上の属性を定義してテスト対象コンポーネントに渡す。。
    const [value. setValue]  useState("");
    // テスト対象コンポーネントのレンダー
    render(<Test value={value} setValue={setValue}>);
    // 検索ボタン要素を取得
    const btnSearch = screen.getByRole("button", {name: "検索"});
    // 検索ボタンをクリック
    fireEvent(btnSearch, new MouseEvent("click", {bubbles: true}));

    ・・・省略・・・
}

要素の取得方法(screen.~)の使い方は慣れる必要があります。

上述で言うと「 screen.getByRole(“button”, {name: “検索”});」の部分などです。

ぱっと見た感じだと、javaScriptでのプログラムと同じように「id」や「name」を指定してアクセスできそうに見えるのですが、これができません。代わりにRoleというもので要素を取得する必要があります。Roleの取得には「getByRole」というコードを実行します。以下のコードを実行することでgetByRoleで取得できる要素を確認できます。

// 要素を指定しないことで情報がコンソール上に出力される
screen.getByRole();

結果の検証

イベント実行後、画面がどのような状態になっていればよいかを検証(テスト)します。

例として、「親コンポーネントに検索条件の入力内容が反映されていればテスト成功」という検証をします。

結果の検証には、expectメソッドを利用して期待値と実際の値が一致していることを確認します。

以下のようなコードとなります。

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

test("jestのテストケース1"){
    // テストメソッドの中で上の属性を定義してテスト対象コンポーネントに渡す。。
    const [value. setValue]  useState("");
    // テスト対象コンポーネントのレンダー
    render(<Test value={value} setValue={setValue}>);

    // テキスト要素を取得 ※今回はユーザIDテキストボックスと仮定
    const txtUserId = screen.getByRole("textbox",{name:"ユーザID"});
    // 検索ボタン要素を取得
    const btnSearch = screen.getByRole("button", {name: "検索"});

    // ユーザIDテキストボックスに値を入力
    fireEvent.change(txtUserId, {target:{value:"testUser"});
    // 検索ボタンをクリック
    fireEvent(btnSearch, new MouseEvent("click", {bubbles: true}));

    // 検証
    // 呼び出し元コンポーネントに入力した値が通知されていること
    // ※コンポーネント側で検索ボタンクリック時に親コンポーネントのsetValueを呼び出していることを想定
    expect(value).toBe(txtUserId.value);
}

上記では、toBe関数を利用して一致していることを検証してますが、検証にはこれ以外にも色々な検証があると思います。

そのほかの検証方法は、Jest公式の以下サイトを参照ください。

Expect · Jest
テストを作成する時に、値が特定の条件に合致することを確認する必要がよくあるでしょう。 expect によって様々な事柄を検証するための数多くの"マッチャ"を利用することができます。

まとめ

Reactアプリケーションの自動テスト入門のまとめ

本記事では、Reactで自動テストを行うための方法を手順を追って紹介しました。昨今ではテストの自動化が定番となってきており、フロントエンドアプリケーションも例外ではありません。フロントエンドアプリケーションのテスト自動化についても基礎知識の習得が必須となってきています。

当記事が、皆様の参考になりましたら幸いです。

この記事を書いた人
z_a_k_i

z_a_k_iと申します。

富山でITエンジニアとして働いています。
0歳児と3歳児を持つ30代メンズです。

このブログでは、以下の内容を紹介しています。

 ⚫︎アプリケーション開発
 ⚫︎富山県の情報発信

皆様に役立つ内容を紹介できるよう精進していきますので、
どうぞよろしくお願いします。

z_a_k_iをフォローする
アプリケーション開発

コメント