03 自動テストの基本
02 章で「テストがあると壊れた瞬間に分かる」を体験しました。この章では、そのテストがなぜ動くのか、基本を押さえます。
なぜ自動テストか
- 手動確認には限界がある: 画面を1つずつ目で照合するのは、パターンが増えると破綻する(02章の手作業がまさにそれ)。
- 回帰(リグレッション)に気づける: 「別の場所を直したら、関係ないはずの所が壊れた」を自動で検知できる。
- リファクタの安全網になる: テストが緑なら、内部構造を作り変えても挙動が保たれていると分かる。安心して直せる。
自動テストは「コードが期待どおり動くか」をプログラムで繰り返し確認する仕組みです。
node:test の最小例
このハンズオンでは、追加ライブラリを入れず Node.js 標準の node:test を使います。
import { test } from 'node:test'import assert from 'node:assert/strict'
test('1 + 1 は 2 になる', () => { assert.equal(1 + 1, 2)})node:test… テストランナー(test()でテストを1件定義)node:assert/strict… アサーション(「こうなっているはず」を表明する)。/strictを付けると厳密比較になり、おすすめ
AAA パターン(準備・実行・検証)
読みやすいテストは、3つのまとまりで書けます。
test('標準課税の商品は税込で表示される', () => { // Arrange(準備):入力を用意する const product = { name: 'ノートPC', price: 100000, tax_category: 'STANDARD', tax_rate: 0.1 }
// Act(実行):テスト対象を呼ぶ const line = toCartLine(product)
// Assert(検証):結果が期待どおりか確かめる assert.equal(line.label, '税込') assert.equal(line.total, 110000)})- Arrange … 準備(入力データ、前提条件)
- Act … 実行(テストしたい関数を1回呼ぶ)
- Assert … 検証(戻り値・状態が期待どおりか)
この3段に分けると、「何を・どうしたら・どうなるべきか」が一目で読めます。
実行方法
# ディレクトリ内のテストを全部実行node --test
# 変更を監視して、保存のたびに自動実行(開発中に便利)node --test --watch
# 特定のファイルだけ実行node --test test/cart.test.js
package.jsonのscriptsに"test": "node --test"を入れておけばnpm testでも実行できます。
よく使うアサーション
| 書き方 | 意味 |
|---|---|
assert.equal(a, b) | a と b が等しい(プリミティブ向け) |
assert.deepEqual(a, b) | オブジェクト・配列の中身が等しい |
assert.ok(value) | value が真(truthy)である |
assert.throws(fn) | fn() が例外を投げる |
例(02章の集計関数):
test('課税と非課税が混ざった注文を正しく振り分ける', () => { const orders = [ { total: 220, tax_rate: 0.1, tax_category: 'STANDARD' }, // 課税 { total: 5000, tax_rate: 0, tax_category: 'EXEMPT' }, // 非課税 ]
const sales = sumSalesByTaxability(orders)
assert.deepEqual(sales, { taxable: 220, exempt: 5000 })})良いテストの性質
- 速い: すぐ実行できると、何度も回せる。だから純粋な計算ロジックを優先してテストする。
- 決定的: 何度実行しても同じ結果。時刻・乱数・外部通信に依存しない。
- 1つのことを検証する: 1テストで欲張らない。落ちたときに原因が一目で分かる。
- 名前が仕様になっている:
'標準課税の注文は税率0%でも課税売上に集計される'のように、テスト名だけで「何を保証しているか」が読める。
02章のテストは、まさに「税率0%でも課税は課税」という仕様をテスト名と検証で表現していました。テストは仕様を実行可能な形で書いたもの、と捉えると腹落ちします。
次へ: 04 テストの設計 →