コンテンツにスキップ

7-1. ユニット・統合・E2Eテストの違い

  • テストをなぜ書くのか
  • ユニットテスト・統合テスト・E2Eテストの役割と違い
  • それぞれをどんな場面で使い分けるか
  • テストピラミッドの考え方

バグを「後で見つける」より「早く見つける」ほうが、修正コストは低い。 テストは、ソフトウェアが意図通りに動くことを機械的に確認する仕組み である。


コードを書くだけでは、次のような問題が起きやすい。

機能を追加した
別の機能が壊れた
気づかないまま本番リリース
利用者がバグに遭遇

テストを書いておくと、この連鎖を早期に止めやすくなる。

機能を追加した
テストを実行
別のテストが失敗
修正してからリリース
目的説明
バグの早期発見本番前に問題を見つけやすくなる
変更への安心感既存の動作を壊していないか確認できる
仕様のドキュメント化テストコードが「こう動くべき」を示す
リファクタリングの支援構造を変えても動作が変わらないことを確認できる

ソフトウェアテストには代表的な 3 種類がある。

ユニットテスト → 部品単体
統合テスト → 部品を組み合わせた動き
E2Eテスト → 利用者の視点で全体を通す

それぞれを詳しく見ていく。


ユニットテストは、関数やクラスといった小さな単位の動作を確認するテスト である。

関数 calcTax(price, rate)
入力 1000, 0.1
期待出力 100
実際の出力と比較
  • 特定の入力に対して正しい値が返るか
  • 境界値(0・負数・最大値など)で正しく動くか
  • エラー条件でどう振る舞うか
項目内容
速度速い(データベースや外部通信を使わない)
安定性安定しやすい(外部依存がない)
範囲狭い(1つの関数や小さなクラス)
書きやすさ比較的書きやすい
# 対象
関数: calcTax(price, rate) → price * rate
# テスト
入力 1000, 0.1 → 期待値 100
入力 0, 0.1 → 期待値 0
入力 1000, 0 → 期待値 0

ユニットテストは「設計の最小単位が正しいか」を確認する。


統合テストは、複数の部品が組み合わさったときの動作を確認するテスト である。

APIエンドポイント
入力バリデーション層
サービス層(ビジネスロジック)
データベース層

これらをつないだ状態で、正しく連携しているかを確認する。

ユニットテストが全部通っても、部品の組み合わせ方が間違っているとバグになる。

部品A: 正しく動く
部品B: 正しく動く
部品AとBの結合: 渡すデータの形式が合わなくて壊れる

統合テストは、こうした「接続部分のズレ」を見つけるために使う。

項目内容
速度ユニットテストより遅い(DBや外部サービスを使うことがある)
安定性外部依存があると不安定になりやすい
範囲中程度(複数コンポーネントの連携)
書きやすさユニットテストより難しい場合が多い
  • API エンドポイントにリクエストを送り、レスポンスのステータスコードと内容を確認する
  • データベースへ書き込み、期待した状態になっているか確認する

E2Eテストは、実際の利用者と同じ操作の流れを端から端まで通すテスト である。

ブラウザ操作
ログイン画面でIDとパスワードを入力
一覧画面が表示される
新しい本を追加する
一覧に追加した本が表示されている

このように、ブラウザ操作から始まり、バックエンド・データベースを通した結果まで確認する。

ユニットテストや統合テストが通っていても、画面の設定ミスや経路の間違いで利用者が使えないことがある。

ユニットテスト OK
統合テスト OK
しかしブラウザの設定でページが表示されない

E2Eテストは「利用者が実際に使える状態か」を確認する最後の砦である。

項目内容
速度遅い(ブラウザ操作・通信・DBアクセスを全て含む)
安定性最も不安定になりやすい(外部依存が多い)
範囲広い(アプリ全体の動作を通して確認)
書きやすさ最も複雑

3 種類のテストをどのくらいの割合で書くかの考え方として、テストピラミッド がある。

/E2E\
/-----\
/ 統合 \
/---------\
/ ユニット \
/ \

ピラミッドのイメージは次のとおりである。

レベル理由
ユニットテスト多い速く・安定していて・書きやすい
統合テスト中程度必要な連携確認に絞る
E2Eテスト少ない遅く・不安定になりやすいため重要な経路に限定する

なぜピラミッド型が推奨されるのか

Section titled “なぜピラミッド型が推奨されるのか”

E2Eテストだけに頼ると、次の問題が起きやすい。

全てE2Eテストにする
テスト実行が遅くなる
テストを実行する回数が減る
バグの発見が遅くなる

逆にユニットテストを厚くすることで、速いフィードバックを得やすくなる。

ただしこれは絶対的な比率ではなく、アプリの性質や状況に合わせて調整する ものである。


7. テストダブル(モック・スタブ)

Section titled “7. テストダブル(モック・スタブ)”

ユニットテストや統合テストでは、実際のデータベースや外部 API を使いたくない場面がある。 そのときに使うのが テストダブル である。

代表的なものを 2 つ押さえておく。

名前役割
スタブ固定の戻り値を返すニセの部品
モック呼ばれた内容(引数・回数など)も記録して検証できるニセの部品

使い分けのイメージをコードで見てみる。

// スタブ:戻り値だけを固定する
function stubBookRepository() {
return {
findAll: () => [
{ id: 1, title: "JavaScript入門" },
{ id: 2, title: "Git基礎" },
]
};
}
// → 「本が2件ある状態」を再現し、ビジネスロジックだけをテストできる
// モック:呼び出し内容も記録する
function mockMailService() {
const calls = [];
return {
send: (to, subject) => calls.push({ to, subject }),
getCalls: () => calls,
};
}
// → メールが正しい宛先・件名で1回だけ呼ばれたか、などを検証できる
戻り値だけ固定したい → スタブ
呼び出し回数や引数も確かめたい → モック

ただし、テストダブルを使いすぎると実際の動作と乖離する恐れがある。 何を確認したいか に合わせて、実物かスタブかを選ぶ。


確認したいこと向いているテスト
関数の計算が正しいかユニットテスト
API と DB が正しく連携するか統合テスト
ユーザーが実際に使えるかE2Eテスト
特定の条件(境界値・エラー)の動作ユニットテスト
ログイン〜操作〜確認の流れ全体E2Eテスト

また、バグが見つかったらテストを書く という習慣も重要である。 同じバグが再び起きても、テストが守ってくれる。

回帰テストとは、修正や機能追加のあとに、以前動いていた部分が壊れていないかを確認するテスト である。

新しい機能を追加した
既存のテストをすべて実行する
壊れていたテストが発見される
意図せず既存の動作を変えてしまったと分かる

回帰テストは専用の「種類」ではなく、ユニットテスト・統合テスト・E2Eテストを使って、変更後に再実行する考え方 である。 テストを積み重ねておくほど、回帰テストの網が大きくなる。


キーワード説明
ユニットテスト関数・クラス単体の動作を確認
統合テスト複数の部品が組み合わさったときの動作を確認
E2Eテスト利用者の操作フローを端から端まで通して確認
テストピラミッドユニット多め・E2E少なめで速く安定したテスト群を作る考え方
スタブ固定値を返すニセの部品
モック呼び出し内容も記録できるニセの部品
回帰テスト修正後に以前動いていた部分が壊れていないかを確認するテスト

演習問題 に取り組んで、3 種類のテストの役割と使い分けを整理しよう。

その後は 7-2. TDD入門・コードレビューの観点 へ進もう。