【Python/TypeScript】意味のあるテストの書き方
KEY TAKEAWAYS
この記事でわかること
- テストの本質的な考え方:何を保証すべきか
- 良いテスト・悪いテストの具体例(Python/TypeScript)
- スナップショットテスト・ゴールデンデータの活用法
- カバレッジ指標の正しい使い方と限界
- 実務で使えるテスト戦略とツール選び
"テストとは、関数に何かを与えて期待した何かが返ってくることを永続的に保障していくもの。そして、ある修正に対する影響範囲を検知するもの。"
テストって結局何のために書くんでしょうか?カバレッジを上げるため?上司に言われたから?いいえ、違います。
テストの本質は「保証」と「検知」です。この関数は正しい入力に対して正しい出力を返す、というシンプルな約束を守り続けること。そして、誰かがコードを変更したときに、その変更が意図しない場所に影響を与えていないかを検知すること。この2つがテストの核心です。
まず押さえておきたい3つの用語
TERM 01
ユニットテスト
関数やメソッド単位の小さなテスト。1つの機能が正しく動くかを検証します。高速で実行でき、バグの原因を特定しやすいのが特徴です。
TERM 02
統合テスト
複数のモジュールやコンポーネントを組み合わせたテスト。API呼び出しやデータベースとの連携など、実際の動作に近い環境でテストします。
TERM 03
スナップショットテスト
ある時点の「正しい状態」を保存し、その後の実行結果と比較するテスト。UIコンポーネントやAPIレスポンスの変更を検知するのに効果的です。
具体例で学ぶ:良いテスト vs 悪いテスト(Python編)
実際のコードで見てみましょう。Pythonとpytestを使った例です。
悪いテスト例
意味がない、または保守コストが高いテスト
def test_always_passes(self): """常にパスするテスト""" assert True # 何も検証していない def test_implementation_detail(self): """実装の詳細をテスト""" todo = Todo.objects.create(title="Test") # Djangoの内部実装に依存 assert todo._state.db == "default" assert hasattr(todo, "_meta") def test_django_framework_behavior(self): """フレームワークの動作をテスト""" todo1 = Todo.objects.create(title="First") todo2 = Todo.objects.create(title="Second") # Djangoが既に保証している機能 assert todo2.id > todo1.id
良いテスト例
目的が明確で、ビジネスロジックを検証するテスト
def test_title_boundary_max_length(self): """境界値テスト: 最大200文字""" max_title = "a" * 200 todo = Todo.objects.create(title=max_title) assert len(todo.title) == 200 def test_title_boundary_exceeds_max_length(self): """境界値テスト: 201文字はエラー""" todo = Todo.objects.create(title="a" * 201) # SQLiteでは保存されるがDB依存の動作 assert len(todo.title) == 201 def test_is_overdue_with_past_date(self): """期限切れ判定ロジックのテスト""" todo = Todo.objects.create( title="Overdue task", due_date=date.today() - timedelta(days=1), ) assert todo.is_overdue() is True
コード例: test_models.py
フロントエンドも同じ:良いテスト vs 悪いテスト(TypeScript編)
React + TypeScript + Vitestでの例です。考え方はバックエンドと変わりません。
悪いテスト例
実装の詳細やクラス名に依存したテスト
it("always passes", () => {
expect(true).toBe(true);
// 何も検証していない
});
it("checks component instance", () => {
const { container } = render(
<TodoForm onSubmit={vi.fn()} />
);
// 実装の詳細(CSSクラス)に依存
expect(container.querySelector(
".todo-form"
)).toBeTruthy();
});
it("has correct form class name", () => {
const { container } = render(
<TodoForm onSubmit={vi.fn()} />
);
// CSSクラス名のテスト(優先度低)
expect(container.querySelector("form"))
.toHaveClass("todo-form");
});良いテスト例
ユーザーの視点でUIの動作を検証
it("submits form with valid data", async () => {
const onSubmit = vi.fn();
const user = userEvent.setup();
render(<TodoForm onSubmit={onSubmit} />);
await user.type(
screen.getByLabelText(/タイトル/i),
"New TODO"
);
await user.selectOptions(
screen.getByLabelText(/優先度/i),
"high"
);
await user.click(
screen.getByRole("button", {name: /作成/i})
);
expect(onSubmit).toHaveBeenCalledWith({
title: "New TODO",
priority: "high",
// ...
});
});コード例: TodoForm.test.tsx | 参考: Vitest Official
実務で使えるテスト手法の比較
| テスト手法 | どんな時に使う? | 具体例 |
|---|---|---|
| 境界値テスト | 入力値の上限・下限付近をテスト | 200文字、201文字、0文字など |
| 同値分割 | 有効な値・無効な値のパターンを代表値でテスト | 優先度: low/medium/high、期限: 過去/今日/未来 |
| ハッピーパス | 正常系の代表的な処理フロー | ユーザー登録→ログイン→データ作成 |
| スナップショット | ゴールデンデータとの一致を確認 | APIレスポンス、コンポーネントの描画結果 |
私が最もおすすめする手法:スナップショットテスト
Pro Tip: ゴールデンデータを使ったスナップショットテスト
ある時点の「正しい状態」を保存しておき、その後の実行結果と比較する手法です。特にAPIレスポンスや複雑なデータ構造のテストで威力を発揮します。
スナップショットテストの何が良いかって?リグレッション(意図しない変更)の検知力が圧倒的なんです。
実装例(Python + Parquet形式)
def test_all_todos_snapshot(self, api_client):
"""TODO一覧APIのスナップショットテスト"""
response = api_client.get("/api/todos/")
data = response.json()
# ゴールデンデータと比較
snapshot_comparator.assert_matches_snapshot(
data,
"todos_all",
exclude_fields=["id", "created_at", "updated_at"],
)
# IDや日時は実行ごとに変わるので除外
# ゴールデンデータはParquet形式で保存
# - 大量データでも効率的
# - 人間が読めるフォーマット
# - バージョン管理可能コード例: test_todos.py | 参考: Effective Snapshot Testing - Kent C. Dodds
実務で使えるおすすめテストツール
pytest
PythonPythonの定番テストフレームワーク。シンプルな記法、豊富なプラグイン、強力なfixtureシステムが特徴。Django、Flask、FastAPIなど主要フレームワークに対応。
Vitest
TypeScriptViteベースの爆速テストフレームワーク。Jest互換のAPIで移行も簡単。TypeScript対応が優れており、ES Modulesネイティブサポート。React/Vueに最適。
Playwright
E2EMicrosoftが開発するE2Eテストフレームワーク。Chromium、Firefox、WebKitをサポート。自動待機機能が優秀で、フレイキーなテストを減らせる。
Django Test
DjangoDjango標準のテストフレームワーク。TestCaseクラスでDBトランザクション管理を自動化。Django特有の機能(ミドルウェア、ビュー、認証)のテストに特化。
参考: pytest | Vitest | Playwright | Django Testing
組織によって変わるテスト戦略
大企業とスタートアップでは、テストの書き方・考え方が大きく異なります。自分の環境に合ったアプローチを選びましょう。
大企業のアプローチ
要件定義〜詳細設計まできっちり作られている場合が多い
- 設計書ベース:設計の各項目が満たされているかを確認
- テスト仕様書:テストケースが事前に定義済み
- トレーサビリティ:要件→設計→テストの紐付けが重要
- 何を保証するか:仕様書に書かれている通りに動くこと
スタートアップのアプローチ
要件がふんわりしていることも多い
- 自分で考える:何を保証すべきかを自分で決める
- ビジネスロジック優先:重要な機能から書く
- 変更に強く:仕様変更を想定したテスト設計
- 何を保証するか:ユーザーにとって重要な動作
筆者の経験から:大企業の場合、正直に言うと設計書があれば「それが全て」です。設計書の項目を網羅的にテストすればOK。一方、スタートアップでは「いい感じにしといて」と言われることも多いので、さっき説明したテストの本質(保証と検知)に立ち返って考えるのが役に立ちます。
カバレッジ指標:固執すべきでないが、無視していいものでもない
「カバレッジ100%目指せ!」とか「カバレッジなんて意味ない」とか、極端な意見を聞くこと、ありませんか?実は、どちらも正しくありません。
カバレッジのメリット
- テストされていない箇所を可視化できる
- チームで目標を共有しやすい(例: 80%以上)
- 重要なロジックの漏れを防げる
カバレッジのデメリット
- 高いカバレッジ = 良いテストではない
- 数値目標が目的化すると意味のないテストが増える
- テストの質は測れない
筆者の結論:目安として使おう
バックエンドは90%以上、フロントエンドは80%以上を目安にしつつ、getter/setterや設定値の確認など優先度の低いテストは除外してOK。重要なのは「ビジネスロジックがしっかりテストされているか」です。2024年の調査では、テスト自動化を導入している企業の76%がカバレッジ指標を何らかの形で活用しています。
参考: Google Testing Blog - Code Coverage Best Practices | Productive Coverage (ICSE 2024)
データで見るテストの現状
プロジェクトで使用されるテストタイプ(2024)
Source: JetBrains Developer Survey 2024
テスト自動化の割合
Source: Global Software Testing Market 2024
データ: JetBrains Developer Ecosystem 2024 | Software Testing Statistics 2024
Column: テスト駆動開発の歴史
ソフトウェアテストの歴史は意外と浅く、体系的な手法が確立されたのは2000年代に入ってからです。Kent Beckが1999年に発表した「Extreme Programming」の中でテスト駆動開発(TDD)を提唱し、それが現代のテストプラクティスの基礎となりました。
2009年にはMartin Fowlerが「Test Pyramid」の概念を広め、ユニットテスト・統合テスト・E2Eテストのバランスについての指針を示しました。この考え方は今でも多くの開発チームで採用されています。
興味深いのは、スナップショットテストが主流になったのはここ5年ほどのこと。Jestが2016年にスナップショットテスト機能を導入し、それ以降フロントエンド開発で広く使われるようになりました。技術の進化とともに、テストの手法も日々アップデートされているんです。
サンプルコードリポジトリ
Python/TypeScriptの実践的なテストコード例(良い例・悪い例・優先度の低い例)
よくある質問 (FAQ)
テスト実装チェックリスト
- テストフレームワークのセットアップ完了
- 境界値テストの実装
- 同値分割テストの実装
- ハッピーパスの確認
- 異常系・エラーハンドリングのテスト
- スナップショットテストの導入
- CI/CDへのテスト組み込み
- カバレッジ指標の確認
もっと詳しく知りたい人へ(参考文献)
- pytest公式ドキュメント - Python テストフレームワーク
- Vitest公式ドキュメント - TypeScript テストフレームワーク
- Playwright公式ドキュメント - E2E テストフレームワーク
- Martin Fowler - Testing Guide - テストの考え方の基礎
- The Practical Test Pyramid - テストピラミッドの実践
- Google Testing Blog - Googleのテスト手法
- Effective Snapshot Testing - スナップショットテストのベストプラクティス
- JetBrains Developer Ecosystem 2024 - 開発者調査レポート
- サンプルコードリポジトリ - この記事で使用したコード例


まだコメントはありません。最初のコメントを残しませんか?