Stack Map新人 Web エンジニアの地図

テストは「動くことの証明」ではなく、「壊れたらすぐ気づける仕組み」です。種類と書き方、そしてバグが隠れやすい「境目」の見つけ方を、
手を動かしながら覚えます。

なぜテストを書くか

テストは、未来の自分とチームのための安全ネットです。

テストの種類(テストピラミッドで見る)

開発の流れの V 字でいう単体・結合・システムテストのうち、ここでは自動で回すものを扱います(E2E テストは、システムテストの一部を自動にしたもの、と考えると分かりやすい)。細かいテストほど速く安く、たくさん書けます。大きなテストほど安心感はありますが、遅く壊れやすいので少しだけにします。この形は Mike Cohn が 2009 年の本で示した「テストのピラミッド」です。段を押すと、中身が出ます。

書き方の基本

テストは「読まれるコード」です。落ちたときに、何が壊れたかすぐ分かるように書きます。

準備・実行・確認に分けた例(JavaScript)

Laravel(Pest)のテスト

Laravel には Pest と PHPUnit が最初から入っていて、php artisan test で動かせます(Laravel の公式の文書の例)。

Vitest のテスト

ファイル名に .test. か .spec. を入れると、テストとして見つけてくれます(Vitest の公式の始め方の例)。

テストデータの作り方(Laravel)

結合テストで最初に詰まるのが、「テストの前に、どんなデータを入れておくか」です。Laravel には、そのための道具がそろっています。

ファクトリーで、要る分だけ作る

$user = User::factory()->create();             // 1 人
$users = User::factory()->count(3)->create();  // 3 人
$user = User::factory()->unverified()->create(); // 状態を変えて

モデルごとに「ふつうの値」を決めておき、テストでは、確かめたい所だけを書きます。

テストごとに、データベースを空に戻す

use Illuminate\Foundation\Testing\RefreshDatabase;

pest()->use(RefreshDatabase::class);

前のテストのデータが、次のテストに残らなくなります。テストの順番で結果が変わる、を防ぎます。

決まったデータは、シーダーで入れる

$this->seed(OrderStatusSeeder::class);

注文の状態の一覧のように、どのテストでも要るデータは、シーダーでまとめて入れます。

考え方のヒントバグを直すときは、まず再現するテストを書く

直す前に、そのバグで落ちるテストを書いておくと、直ったことと、もう戻らないことを確かめられます。デバッグの基本の流れの最後の歩(戻らないようにする)と同じ考えです。

出典: Laravel「Database Testing」 / Laravel「Eloquent: Factories」

練習: 境目(境界値)でバグを見つける

年齢で料金が決まる関数に、間違いが 1 つ隠れています。年齢を選んでテストを足し、仕様どおりか確かめてください。間違いの場所は「新しい問題」を押すたびに変わります。

仕様
年齢仕様(期待)関数の答え結果

同じ扱いのグループと、境目の値

全部の年齢を試すことはできません。同じ扱いになる値をグループに分け(同値分割)、各グループから代表を 1 つ選びます。そのうえで、間違いが起きやすいグループの端(境界値)の前後を試します。

テストの代役(テストダブル)

本物のメール送信や外の API をテストで動かすと、遅く不安定で、ときには本当に送ってしまいます。本番の部品の代わりに置くものを、まとめて「テストダブル」(代役)と呼びます。この分け方は Gerard Meszaros の整理を、Martin Fowler が紹介したものです。

外のもの・時刻・乱数を固定する

カバレッジ(テストで通ったコードの割合)

テストを動かしたとき、コードのどれだけが実行されたかの割合です。Laravel なら php artisan test --coverage で出せます。

Martin Fowler は、カバレッジは「テストされていない所を見つけるには役に立つが、テストの良さを表す数字としてはほとんど役に立たない」と書いています。

100% でも見落とす例

上の練習で 3 歳・9 歳・30 歳・70 歳の 4 つだけを試すと、料金の関数の行はすべて通ります(カバレッジ 100%)。それでも、境目の間違いは見つかりません。大事なのは「何を確かめたか」です。

CI で毎回、自動で回す

テストは、書いても動かさなければ守ってくれません。プッシュやプルリクエストのたびに自動で全部動かし、落ちたらマージしないようにします。Git「チームの流れ」へ。

ときどき落ちる「不安定なテスト」

同じコードなのに、通ったり落ちたりするテストのことです。Google は 2016 年に、テストの実行のおよそ 1.5% が不安定な結果を出し、テストのほぼ 16% になんらかの不安定さがあると報告しています。

よくある原因

  • テスト同士が、順番やデータを共有している
  • 非同期の処理を待ちきっていない
  • 外のサービスに本当につないでいる
  • 今の時刻に頼っている
  • 前のテストの後片付けができていない

どう扱うか

Martin Fowler は、不安定なテストを別の場所に「隔離」して、健康なテストの結果を信じられるようにすることを勧めています。ただし、隔離したテストはすぐに直します。消したり、放っておいたりはしません。

AI 時代のテスト

AI が書くコードが増えるほど、テストは「AI の仕事を確かめる道具」として大事になります。AI の機能そのもののテストには、ふつうのテストとは違う工夫が要ります。評価の体験はAI を組み込んだアプリのタブへ。

やりがちなミス(チェックリスト)

自分のテストで確かめたら、チェックを付けてみてください(この端末にだけ保存されます)。