3秒でわかる
作ったものが期待どおり動くかを実際に動かして確かめる作業。壊れた箇所を早く小さく見つけ、変更を安心して続けるために行います。
30秒図解
もう少し詳しく
どういうものか
テストは、作ったプログラムが期待どおりに動くかを実際に動かして確かめる作業です。人が画面を触って確認する手動テストと、確認の手順自体をコードで書いて機械に繰り返させる自動テストがあります。開発の現場でテストと言うとき、多くは後者を指します。
範囲で層に分けるのが一般的です。関数やクラス単体を確かめる単体テスト、データベースや外部サービスとつないで確かめる結合テスト、利用者と同じ手順で画面を操作する E2E テストです。下の層ほど速くて原因を特定しやすく、上の層ほど遅い代わりに本番に近い確認ができます。
なぜ必要か
変更を続けるためです。機能が増えるほど、直した箇所と無関係に見える場所が壊れます。手で全画面を確認し直すのは現実的でないため、確認手順をコードにして毎回自動で走らせます。テストがある状態は、書き換えてよい範囲がはっきりしている状態でもあり、リファクタリングの前提になります。
不具合を見つける費用も変わります。実装直後に見つかった誤りは数分で直りますが、公開後に利用者から報告される誤りは、調査と再現と修正と再公開で桁違いの手間になります。
具体例
Node.js の標準テストランナーで書く単体テストです。
import test from "node:test";
import assert from "node:assert/strict";
import { priceWithTax } from "./price.js";
test("税込み価格を切り捨てで返す", () => {
assert.equal(priceWithTax(100), 110);
assert.equal(priceWithTax(105), 115);
});
test("負の金額はエラーにする", () => {
assert.throws(() => priceWithTax(-1));
});期待値を先に書き、実行結果と突き合わせる。どの言語でもこの形は共通です。
つまずきやすいところ
正常系だけを書いて満足しがちです。不具合が出るのは境界と異常系で、ゼロ件、空文字、上限ちょうど、想定外の型といった入力を並べたときに初めて穴が見えます。
実行のたびに結果が変わるテストも困りものです。現在時刻や乱数、外部 API をそのまま使うと、原因が自分のコードにないのに失敗します。時刻や通信は差し替えられる形にしておきます。網羅率の数字を目標にするのも本末転倒で、通しただけで何も確かめていないテストでも数字は上がります。確かめたい振る舞いが名前になっているか、を基準にします。
覚え方
テストは「壊れたことに、自分で気付く仕組み」。誰かに報告される前に落ちるほど価値があります。