見出し画像

Reactで私たちは何をテストするべきか

私たちは何をテストするべきか

Reactフロントエンドは入力 が UI の操作なら最終出力も UI の状態でどっちもつかみどころのないものという、テストするには非常に不都合な宿命です。

純粋なロジック部分については、もちろんテストは必要だと思う。
でも個々の View コンポーネン トをテストしようとするなら、title という Props に 'Foo' という文字列を与えたら <title> タグの 中に Foo が表示される、みたいなテストになります。

そもそもプロダクトが大きく変わっていく局面で は膨大なテスト自体が変化への負債になりかねない。

フロントエンド開発において、何をテストするべきか、テストする労力に対してその効果が見 合うのかが明確じゃないせいだと思う

1. 設計者の意図通りに機能が実現されているかの確認
2. 新規に追加した全ての処理に破綻がないかの確認
3. 既存の機能を破壊していないかの確認
4. モジュラリティの確保

3 は TypeScript でコードを書いていることによる Null 安全性や型整 合性の確保によって、すでにある程度実現できていると思う。
ソフトウェアのバグで最も多いものが Null アクセスの例外だからね

4モジュラリティとは端的に言えば、不要な他からの依存が切れていて、他からの境界が自明になっ ている状態。つまりモジュールとして分離されていて、独立性が高く扱いやすいこと。

1、2のテストにいて今回やりましょう

Javascript のテスト用ツールはいろいろありますが、Facebook製の jest というテスト用フレームワークを使う。

インストール

$ npm init -y
$ npm install --save-dev typescript jest @types/jest ts-jest

それぞれ以下の通り変更&作成します。

package.json

{
 // ...
 "scripts": {
   "test": "jest"
 },
 "jest": {
   "moduleFileExtensions": [
     "ts",
     "tsx",
     "js"
   ],
   "transform": {
     "^.+\\.(ts|tsx)$": "ts-jest"
   },
   "globals": {
     "ts-jest": {
       "tsConfigFile": "tsconfig.json"
     }
   },
   "testMatch": [
     "**/__tests__/*.spec.+(ts|tsx|js)"
   ]
 },
 // ...
}

npm test で jest のテストを起動するようにコマンドを設定し、jestの設定値を追加しています。

tsconfig.json

{
 "compilerOptions": {
   "target": "es5",
   "module": "commonjs",
   "outDir": "./dist",
   "strict": true,
   "esModuleInterop": true,
   "sourceMap": true
 },
 "include": [
   "./src/**/*.ts"
 ]
}

tsconfig.json は Typescript のコードをコンパイルする際の設定値です。

今回は “src” 以下にコード、”__tests__” 以下にテストコードを配置します。

あとは生成された Jest の設定ファイル jest.config.js にて testEnvironment: "jsdom" に書き換える。
今回のテスト対象はブラウザ実行される JavaScript なので、jsdom を指定する。

React を テストするためのライブラリを導入する
React コンポーネントをテストするライブラリは複数あるが、公式が推奨している React Testing Library(RTL) を導入する。

yarn add -D @testing-library/react @testing-library/jest-dom

@testing-library/react ではコンポーネントのレンダリングや出力のために導入する。@testing-library/jest-dom では toBeInTheDocument() のような Jest の Matcher を拡張する。これによって、「Document 上に条件に合致するコンポーネントはレンダリングされているか」などの確認ができる。

テストツール選択理由、人気NO1

スクリーンショット 2020-12-18 午前4.41.13


React Test Library の挙動を理解する
RTL の詳細な使い方は下記がわかりやすい。

https://qiita.com/ossan-engineer/items/4757d7457fafd44d2d2f

今回は自分整理して、テスト作業を説明致します。

手順ステップ1:Renderテスト

Renderとはデータ構造で記述された情報

次に、reactコンポーネントとテストの例を示します。
まず以下のようなテスト対象のコードを作成します
./src/Render.ts


import React from "react";

const Render = () => {
 return (
   <div>
     <h1>React Testing Library 1</h1>
     <input type="text" />
     <button>Click1</button>
     <button>Click2</button>
     <p>App Design</p>
     <span data-testid="copyright">@React</span>
   </div>
 );
};

export default Render;
 

次にテストコードを作成します。
./__tests__/Render.spec.ts

使い方は下記サイトご参考に

https://github.com/A11yance/aria-query#elements-to-roles

import React from "react";
import { render, screen } from "@testing-library/react";
import Render from "../Render";

describe("Rendering", () => {
 it("Should render all the elements correctly", () => {
   render(<Render />);
   //全体テスト
   //screen.debug();
   //タグ存在テスト
   //screen.debug(screen.getByRole("heading"));
   //https://jestjs.io/docs/en/expect
  //存在の場合はtoBeTruthy、無い場合toBeNullと予想します
   expect(screen.getByRole("heading")).toBeTruthy();
   expect(screen.getByRole("textbox")).toBeTruthy();
   //同じタグ複数存在する場合getAllByRole
   expect(screen.getAllByRole("button")[0]).toBeTruthy();
   expect(screen.getAllByRole("button")[1]).toBeTruthy();
  //内容をテストする場合
   expect(screen.getByText("App Design")).toBeTruthy();
   //異常内容をテストする場合
   expect(screen.queryByText("エラーxxxx")).toBeNull();
  //タグのID名テストする場合
   expect(screen.getByTestId("copyright")).toBeTruthy();

   //screen.debug(screen.getByText("App Design"));
 });
});

プロジェクトのルートからnpx jestを実行すると、jestはあなたのテストを実行します。

ここから先は

9,841字 / 1画像
この記事のみ ¥ 980

この記事が気に入ったらサポートをしてみませんか?