Yuto Blog
rss-iconx-icongithub-iconyoutube-icon

読書メモ: フロントエンドテスト開発テスト入門

感想

業務でテストを書くことは今までも少しあったのですが、その際には「バグを早期発見することで、保守性が上げる」「長期的にはメリットがあるけど、短中期的にはコストがかかる」みたいな認識だったのと、自分自身クライアントワークだったので、そこまでフロントエンドのテストについて学んでいませんでした。

ですが最近は関わるプロジェクトが 5 年 / 10 年と続くようなプロジェクトに変わってきました。 そこで体験したこととして、テストに力を入れているかいないかで開発速度にかなり差がある気がしたのと、「いいテストコードを書くには、いい設計をしないと書けない」ということも学べたので、これを機にテストを学んでみようと思いました。

第六章まではテストについて色々説明が多かったので、軽く自分のメモとして残しています!

本書

https://www.amazon.co.jp/%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E9%96%8B%E7%99%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88%E5%85%A5%E9%96%80-%E4%BB%8A%E3%81%8B%E3%82%89%E3%81%A7%E3%82%82%E7%9F%A5%E3%81%A3%E3%81%A6%E3%81%8A%E3%81%8D%E3%81%9F-%E5%90%89%E4%BA%95%E5%81%A5%E6%96%87/dp/4798178187/ref=tmm_hrd_swatch_0?_encoding=UTF8&qid=&sr=

第一章: テストの目的と障害

テストを書く目的

事業の信頼

健全なコードを維持するため

実装品質に自信を持つため

円滑なコラボレーションのため

リグレッションを防ぐため

リグレッション(regression)とは、日本語で「回帰」「後戻り」「後退」といった意味を持つ英単語です。 システム開発などのシーンにおいては、修正したバグや不具合が復活したり、ソフトウェアのバージョンアップで機能が低下したりすることを指します。

テストを書くと、時間が節約できる理由

テストを全員が書くためには?

第二章: テスト手法とテスト戦略

ここでは「フロントエンドのテスト範囲と目的」いついて学びました

テストの範囲

静的解析

単体テスト

結合テスト

E2E テスト (End to End テスト)

テストの目的

テストタイプは検証目的に応じて設定され、テストタイプごとに適したテストツールが存在する ツール単体で実現するものもあれば、組み合わせることで実現するものもある

機能テスト(インタラクションテスト)

非機能テスト(アクセシビリティテスト)

リグレッションテスト

テスト戦略モデル

などもある

アイスクリームコーン型、テストピラミット型

テスティングトロフィー型

第三章: はじめての単体テスト

テストの構成要素

テストの構成要素

テストグループの作成

闘値と例外処理

例外のスローを検証するテスト

https://jestjs.io/docs/expect#tothrowerror

用途別のマッチャー

真偽値の検証

数値の検証

非同期処理のテスト

非同期処理のテストを書く場合に意識すること

第四章: モック

モックを使用する目的

モックの用語整理

スタブの目的

スパイの目的

モックモジュールを使ったスタブ

Web API のモック基礎

import * as Fetchers from "../fetchers";

jest.mock("../fetchers");

https://jestjs.io/docs/jest-object#jestspyonobject-methodname

https://jestjs.io/docs/mock-function-api#mockfnmockresolvedvalueoncevalue

Web API のモック生成関数

function mockGetMyArticles(status = 200) {
  if (status > 299) {
    return jest.spyOn(Fetchers, "getMyArticles").mockRejectedValueOnce(httpError);
  }
  return jest.spyOn(Fetchers, "getMyArticles").mockResolvedValueOnce(getMyArticlesData);
}

モック関数を使ったスパイ

実行されたことの検証

https://jestjs.io/docs/mock-function-api#jestfnimplementation

実行された回数の検証

https://jestjs.io/ja/docs/expect#tohavebeencalledtimesnumber

第五章: UI コンポーネントテスト

UI コンポーネントの基礎知識

MPA と SPA の違い

UI コンポーネントのテスト

必要なライブラリのインストール

https://www.npmjs.com/package/jest-environment-jsdom

https://testing-library.com/docs/ecosystem-jest-dom/

https://testing-library.com/docs/react-testing-library/intro/

https://github.com/testing-library/user-event

インタラクティブな UI コンポーネントテスト

type Props = {
  onChange?: React.ChangeEventHandler<HTMLInputElement>;
};

export const Agreement = ({ onChange }: Props) => {
  return (
    <fieldset>
      <legend>利用規約の同意</legend>
      <label>
        <input type="checkbox" onChange={onChange} />
        当サービスの<a href="/terms">利用規約</a>を確認し、これに同意します
      </label>
    </fieldset>
  );
};
import { useId, useState } from "react";
import { Agreement } from "./Agreement";
import { InputAccount } from "./InputAccount";

export const Form = () => {
  const [checked, setChecked] = useState(false);
  const headingId = useId();

  return (
    <form aria-labelledby={headingId}>
      <h2 id={headingId}>新規アカウント登録</h2>
      <InputAccount />
      <Agreement
        onChange={(event) => {
          setChecked(event.currentTarget.checked);
        }}
      />
      <div>
        <button disabled={!checked}>サインアップ</button>
      </div>
    </form>
  );
};

UI コンポーネントのスナップショットテスト

第六章: カバレッジレポートの読み方

カバレッジレポートの概要

カバレッジレポートの構成

参考

https://jsprimer.net/basic/async/

https://testing-library.com/

0