テストという概念を知ったのは、本番環境を壊した翌週のことだった。
ハッチに「テストしてたら気づけたかもな」と言われ、悔しかった。でも、「テスト」が具体的に何を指すのかすら、わかっていなかった。コードを実行して動くか確認すること? それならやっていた。ブラウザで表示を見て、ボタンを押して、動いたら「OK」としていた。
でも、エンジニアの言う「テスト」は、どうやらそれとは違うらしい。
テストって具体的に何するの? 動くか確認するのとは違うの?
手動で「動くか確認する」のもテストの一種ですが、エンジニアリングで言う「テスト」は通常、自動テストを指します。
テストコードを書いて、プログラムが期待どおりに動くことを自動的に確認する仕組みです。たとえば:
test('1 + 1 は 2 になる', () => {
expect(1 + 1).toBe(2);
});このコードは「1 + 1の結果が2であること」を自動的に確認します。
1+1が2になるかどうかをわざわざ確認するの? 当たり前じゃない?
これは最もシンプルな例です。実際には、もっと複雑なロジックをテストします。「ユーザーがログインしたとき、正しいページにリダイレクトされるか」「データが空のとき、エラーメッセージが表示されるか」など。
コードが複雑になるほど、人間が手動で全パターンを確認するのは不可能になります。テストコードを書いておけば、変更するたびにボタン一つで全パターンを自動チェックできます。
ボタン一つで全パターンを自動チェック。
人事の評価制度を変更するとき、「全社員に影響がないか」を手動で確認するのは不可能だ。だから制度変更のたびにトラブルが起きる。もしテストのように、「この変更で誰にどんな影響が出るか」を自動チェックできたら、どれだけ助かるか。
クロにVitestというテストランナーを教えてもらい、最初のテストを書いた。
$ npx vitest run
✓ src/utils.test.js (3 tests) ✓ formatDate は正しい形式で日付を返す ✓ formatDate に無効な値を渡すとエラーになる ✓ truncateText は指定文字数で切り詰める
Test Files 1 passed (1) Tests 3 passed (3)
3つの緑のチェックマーク。全部passed。
たった3つのテストだけど、「自分のコードが正しく動いている」という確信が、テストを書く前とはまったく違う。ブラウザで手動確認したときの「たぶん大丈夫」と、テストが全部通ったときの「確実に大丈夫」は、天と地の差がある。
テスト、全部通った。なんか安心する。
テストが通ると安心しますよね。この安心感が、テストを書くモチベーションになります。
次は、テストが失敗するケースも体験してみましょう。わざとバグを入れてみてください。
言われたとおり、わざとバグを入れた。テストが赤くなった。「Expected 2, received 3」。期待値は2なのに、3が返ってきたと。
この赤いメッセージは、エラーの海で見た赤とは違った。これは「お前のコードが間違っている」というより、「ここにバグがあるよ」と教えてくれるガイドだ。テストがなければ、このバグは本番で発見されていたかもしれない。
テストにハマり始めたのは、スキップテストに出会ったときだ。
既存のプロジェクトのテストコードを見ていたら、test.skip と書かれたテストがいくつかあった。スキップ。飛ばされているテスト。
スキップはなんでスキップされてるの?
test.skipは、一時的にテストの実行を飛ばすための機能です。理由はさまざまですが、よくあるのは:
- まだ実装していない機能のテスト
- 環境依存で特定の環境では動かないテスト
- バグがあるが今すぐ直せないテスト
ただし、skipが多いのは健全な状態ではありません。スキップされたテストは、テストされていないコードがあることを意味します。
スキップする理由を全部つぶしてください
スキップされていたテスト: 5件
- データベース接続テスト → モックに置き換え ✓
- 画像リサイズテスト → sharp依存を修正 ✓
- API レートリミットテスト → タイムアウト設定追加 ✓
- 日付フォーマットテスト → タイムゾーン固定 ✓
- ファイル書き込みテスト → tmpdir使用に変更 ✓
結果: skip 0件、全テストpass
5件のスキップテストを全部潰した。一つ一つ、スキップされている理由を調べ、根本的に解決した。
この作業は、不思議なほど楽しかった。人事でいえば、「形骸化した制度を一つずつ見直して、ちゃんと機能する状態にする」のに似ている。スキップテストは、形骸化した社内制度だ。存在はしているけど、誰も使っていない。使えない理由がある。その理由を一つずつ潰していく。
全部のスキップ消した。気持ちいい。
素晴らしいです。スキップテストをゼロにするのは、コードの品質に対する良い姿勢です。テストは書くだけでなく、メンテナンスし続けることが重要です。
テストを知ってから、コードの書き方が根本的に変わった。
以前は「動くコード」を書いていた。今は「テストできるコード」を書こうとしている。
この違いは大きい。テストできるコードは、必然的に構造が整理される。一つの関数が一つのことだけをやる。入力と出力が明確になる。副作用が分離される。テストしやすさを意識すると、コード自体が良くなる。
テスト書き始めたのか。早いな。
本番壊したからね。怖い思いしたから、テストに逃げ込んだとも言える。
逃げ込むんじゃなくて、学んだんだろ。失敗から学んでテストを書く。正しい進化だよ。
ちなみに、面接で「テスト書いてますか?」って聞いたことある?
ない。正直、テストの重要性がわかってなかったから。今なら聞く。「テストをどう書いてますか」じゃなくて、「テストが落ちたとき、どう対処しますか」って。
いい質問だな、それ。
テストが落ちたとき、どう対処するか。テストを消す人もいれば、skipにする人もいれば、根本原因を直す人もいる。その対処法に、エンジニアとしての姿勢が出る。
テスト導入前:
- コード変更 → 手動確認 → デプロイ → 祈る
- バグ発見: 本番で(ユーザーが踏む)
- 安心感: ゼロ
テスト導入後:
- コード変更 → テスト実行 → 全パス確認 → デプロイ
- バグ発見: テスト実行時(自分で気づく)
- 安心感: 高い
「デプロイして祈る」から「テストして確認する」へ。
テストを知った日から、僕のコードは少しだけ大人になった。まだまだ未熟だけど、少なくとも「動くかどうかわからないけど出す」はやめた。「テストが通ったから出す」に変わった。
小さな変化だけど、たぶん一番大きな変化だ。