ここでの初期状態とはUIコンポーネントテストを書くとき設定するpropsのことである。 propsが複数ある場合、全てのパターンを網羅しようとすると組み合わせの数次第ではテスト数が膨大になる。 すると、テストケースの維持やメンテナンスが難しくなる。
自動テストの導入は品質向上のきっかけとしたり、変更時のデグレードを防ぐために行なっている。それにも関わらず、テストケースのメンテナンスに悩殺されていれば意味がない。 ほどほどに、しかし必要なテストは書いておきたい。どのように初期状態を設定すれば良いだろうか。
TODOリストを元にパターンを洗い出す
TODOリストで先に仕様を整理しているため、それを元に取りうるpropsパターンを全て洗い出す。最初から過不足なく書こうとすると手が止まってしまうため、まずはパターンを洗い出す。パターンの出し方は積の法則の考え方を使って出すとわかりやすい。『数学Ⅰ・A 基礎問題精講(四丁増補版、2018, p168)』1では、積の法則は次のように定義されている。
2つの事象A, Bの起こり方がそれぞれp通り, q通りあるとき, A, Bがともに起こる場合の数は p × q通り
propsに当てはめて考えてみる。例えば、propsにcolor
とcount
を設定できるStarRating
コンポーネントがあったとする。
import React from "react"; import { faStar } from "@fortawesome/free-regular-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; type StarRatingProps = { color: "red" | "blue" | "yellow"; count: number; }; export default function StarRating({ color = "red", count = 3, }: StarRatingProps): JSX.Element { return ( <> {[...Array(count)].map((n, i) => ( <FontAwesomeIcon key={i} icon={faStar} color={color} /> ))} <p>{`星の数は${count}個です`}</p> </> ); }
StarRatingは星の数でレート(評価)を表現するUIコンポーネントである。color
は星の色を設定できるpropsである。red
・blue
・yellow
の3種類が設定できる。一方、count
はレートの数を管理している。星1つから星5つをつけることができる。また、countの値を使って「星の数はいくつか」を表示するテキストも表示している。
Ratingコンポーネントが取りうる状態はいくつだろうか。積の法則を元に考えると、props colorのパターン × props countのパターン × props count のテキストを表示するパターン = 3 × 5 × 5 = 75パターンとなる。
重複しているパターンを取り除く
パターンを洗い出すことはできたが、全ての場合の数をテストするのは大変である。先に述べたRatingコンポーネントだけでも75ケース存在する。propsが1つ追加されると積の法則でどんどん増えてしまう。こうなると要件の追加・変更時に修正範囲が膨大となり、テストが機能しなくなってしまう。
そこで、すでにテスト済みのものは取り除けないか考える。整理したTODOと比較し、「propsの値に応じて動きが変わる組み合わせはないか」を探す。次に、すでに存在するパターンは取り除くようにする。
Ratingコンポーネントの例では「propsの値に応じて動きが変わる組み合わせ」は存在しない。color
がred
のときに必ず星三つをつけるようなルールは存在しないためである。よって、テストケースは和の法則で考えれば良くなる。props colorのパターン + props countのパターン + props count のテキストを表示するパターン = 3 + 5 + 5 = 13パターンとなる。
さらに考えると、count
は1回テストしてしまえば数が変わったときもcount
の数だけ星を表示する点では同じである。count=5
のときは表示しない、などの特殊な仕様があるならテストケースに入れるべきだが、そうではない。よってcount
は最低1回テストすれば良い。テキスト表示の場合も同じ考え方が利用できる。
結果的にテストケースは次の5パターンまで絞れる。
color=red
のとき星の色が赤色で設定されているcolor=blue
のとき星の色が青色で設定されているcolor=yellow
のとき星の色が黄色で設定されているcount
の数だけ星が描画されている- 星の数を示すテキストが
count
の値を使って描画されている
重複しているパターンはUIコンポーネントテストの範囲だけでなく、ビジュアルリグレッションテスト2やE2Eテスト3など、他の自動テストでカバーできるパターンはテストしなくても良い。不具合が多く出てくる部分は重複していてもテストケースに入れておく。壊れて複数回直すよりマシだからである。
この例だとcolor
の値と設定される色がおかしくなっていないかは見た目 = ビジュアルリグレッションテストの領域が得意なものである。1から3は省略するか、color
の設定が有効に働くかだけをUIコンポーネントテストで確かめる。もしビジュアルリグレッションテストがなければ1から4まで省略せずに記載するか、代わりの手段を考える。
今回はcolor
のテストを取り除く方向で考える。テストケースは次のようになる。
count
の数だけ星が描画されている- 星の数を示すテキストが
count
の値を使って描画されている
パターン : テスト = 1 : 1になるようにpropsを設定する
重複しているパターンを除外できれば、あとはテストケースの雛形を作りテストを書くだけである。 デフォルト値が設定されている場合は変えた方が良い。実はデフォルト値しか設定できませんでした、みたいなことがあり得るため。
import React from "react"; import { render } from "@testing-library/react"; import StarRating from "./"; it("countの数だけ星が描画されている", () => { // デフォルト値は3なので変更した値を渡す const content = render(<StarRating color="red" count={5} />); // 星の要素を取得 const stars = content.getAllByTitle("star"); // 要素数は5個 expect(stars).toHaveLength(5); }); it("星の数を示すテキストがcountの値を使って描画されている", () => { // デフォルト値は3なので変更した値を渡す const content = render(<StarRating color="red" count={4} />); // 意図通りのテキストになっているか確認 expect(content.getByText("星の数は4個です")).toBeTruthy(); });