ユニットテストと結合テストの境界線

· · テスト, ユニットテスト, 結合テスト, テスト設計, Windows開発, C# / .NET

まず結論

テストの境界は、コードの置き場所ではなく、何の不確実性を減らしたいかで決めます。

  1. 純粋ロジックはユニットテスト(判断のテスト)
  2. 接続・配線・変換・環境差は結合テスト(接続のテスト)
  3. どちらでも検証できるなら、まずユニットテスト
  4. 結合テストは広く重くするより、境界を狭く絞る

判断表

確かめたいもの 主力にするテスト 補足
金額計算、割引、状態遷移、入力検証 ユニットテスト 入力パターンを厚く回したい
例外の分類、エラーメッセージ選択、リトライ判断 ユニットテスト 実 I/O なしで意味が完結する
Repository の SQL / ORM 変換、transaction 結合テスト 実 DB や実 provider の挙動が本題
JSON / XML / CSV の serialize / deserialize 結合テスト フォーマットのズレは fake では見つけにくい
ルーティング、モデルバインディング、フィルター 結合テスト フレームワークとの接続確認
ViewModel や Presenter の状態遷移 ユニットテスト UI を立てなくても意味がある
実際の Binding、Dispatcher、control lifecycle 結合テスト フレームワークとスレッドの挙動が主題
ファイルパス、権限、ロック、文字コード 結合テスト OS とファイルシステムの実挙動が必要
COM 登録、32bit/64bit、STA/MTA、DLL ロード 結合テスト 環境差とプロセス境界が主題
アプリ全体の起動、主要ユースケースの通し確認 E2E / スモーク 本数は少なくてよい

ユニットテストで持つべきもの

ユニットテストに向くのは、外界を取り去っても意味が残る責務です。

  • 業務ルール、分岐、状態遷移
  • 入力検証、エラー分類
  • リトライ方針の決定
  • ViewModel / Presenter の状態変化

特に組み合わせが多いものほどユニットテストへ寄せる価値が高いです。分岐条件が増えるほど、結合テストで全部を回すのは重くなります。

ユニットテストの鉄則

  • 現在時刻は注入する
  • GUID や乱数は差し替え可能にする
  • sleep で待たない
  • 実 DB や実ファイル、実ネットワークに触れない

mock が増えすぎる場合

mock が 7 個、setup が本体より長い状態になるなら、たいてい「そのクラスが責務過多」か「本当は結合テストで見るべき配線をユニットテストに押し込んでいる」かのどちらかです。

結合テストへ上げる 4 つの境界

1. フォーマットの境界

JSON/XML/CSV、DB の schema と mapping、nullable/precision/timezone、文字コードや BOM、改行コード。serialize/deserialize が入る境界は結合テスト候補です。

2. 配線の境界

DI 登録、設定の bind、ルーティング、モデルバインディング、フィルター、middleware、host の起動、イベント配線。複数の実部品が正しくつながっているかを確認します。

3. 環境の境界

ファイル権限、共有フォルダ、ファイルロック、管理者権限、COM 登録、32bit/64bit、STA/MTA、DLL のロード元。Windows 開発では特に重要です。

4. 時間の境界

timeout、cancellation、retry の実挙動、timer 駆動、バックグラウンド処理の停止、race condition、shutdown 時の終了順序。「判断」と「実挙動」を分けることが大事です。

  • 何回まで retry するか → ユニットテスト
  • 実際に timeout が効くか → 結合テスト

よくある判断ミス

  1. Repository を mock して満足する - SQL の正しさや transaction は結合テストでしか分からない
  2. Controller のユニットテストでフレームワークまで見ようとする - routing や model binding は結合テスト側
  3. 結合テストで入力パターンを総当たりする - 分岐の総当たりはユニットテスト、境界の代表ケースは結合テスト
  4. CI から外部サービスの本番系をそのまま叩く - ローカル DB、一時ディレクトリ、test host、専用の test environment を使う

おすすめの 3 層構成

主力 何を置くか
コア層 ユニットテストを厚く 業務ルール、状態遷移、入力検証、エラー分類
境界層 狭い結合テストを置く DB、ファイル、HTTP、serializer、DI、設定、COM、権限
全体層 少数のスモーク/E2E 起動確認、主要フロー、重大障害の再発防止

数で厚くなるのはユニットテスト、境界の濃さで厚くなるのが結合テストです。

迷ったときの 5 問

  1. in-memory の fake で置き換えても、確認したい意味は残るか → 残るならユニットテスト
  2. 壊れたときに疑うのは、ロジックではなく接続や設定ではないか → そうなら結合テスト
  3. DB/ファイル/serializer/DI/route/OS/権限/bitness/thread が主題か → そうなら結合テスト
  4. 大量の入力パターンを高速に回したいか → そうならユニットテスト
  5. そのテストが落ちたとき、何を直せばよいかがすぐ分かるか → 分からないならテストの層が混ざっている

まとめ

  • ユニットテストは判断のテスト
  • 結合テストは接続のテスト
  • 分岐の総当たりはユニットテスト
  • フォーマット、配線、環境、時間は結合テスト
  • 全体の通し確認は少数のスモーク/E2E

最も避けたいのは「mock で本物との接続まで証明した気になる」「結合テストで全部の分岐を回そうとする」「テストの責務を混ぜる」の 3 つです。迷ったら、その不具合は「判断」が壊れるのか「接続」が壊れるのかを先に見てください。

関連記事

参考資料

関連する記事

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

Windows Sandboxで開発検証を高速化する

Windows サンドボックスを使った Windows アプリ開発の検証手順を整理した実務向けガイドです。クリーン環境での初回インストール確認、管理者権限問題の切り分け、権限不足やリソース不足の再現を、.wsb 設定ファイルと CLI の使い分けまで含めて解説します。

記事を読む

未想定例外発生時の対応判断フロー

想定していない例外が発生したとき、アプリを終了すべきか継続すべきかを判断するための実用的な指針をまとめた記事です。失敗単位、共有状態、外部副作用、ネイティブ境界の観点から3段階の選択肢と判断表で整理し、設計判断に直接使えます。

記事を読む

Windowsアプリのセキュリティチェックリスト

WPF・WinForms・WinUI・C++・C# など Windows アプリ開発で最低限外したくないセキュリティ項目を、権限・署名・秘密情報・通信・入力・DLL・ログの観点でチェックリスト化し、リリース前に何を確認すべきか整理した記事です。

記事を読む

関連トピック

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

このテーマがつながるサービス

この記事は次のサービスページにつながります。近い入口からご覧ください。

ブログ一覧に戻る