更新履歴(3件・最終更新 2026年08月02日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- 記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
- 外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
- C#と.NETを前提にしていること、コード例がxUnitであることを冒頭で明示しました。ユニットテストと結合テストの最小例をそれぞれ新設し、テストダブルの分類表(stub、mock、fake)を追加して「mockが7個」という記述の意味につなげました。E2Eをこの記事でどう扱うかも明記しています。
- 初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589746)
この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。
小村 豪(2026)「ユニットテストと結合テストの境界をどう引くか」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589746 https://staging.comcomponent.com/blog/2026/03/25/004-unit-test-vs-integration-test-boundary-guide/
- DOI(最新版)
- 10.5281/zenodo.21589746
- DOI(この版)
- 10.5281/zenodo.21732760
テスト設計の話で、毎回地味に難しいのが、どこまでをユニットテストに押し込み、どこからを結合テストへ上げるかです。
ここで危ないのは、
- 速く回したいから、何でもユニットテストにする
- 本物に近いから、何でも結合テストにする
という両極端です。
前者はモックだらけになって本番で壊れるポイントを見落としやすく、後者は遅くて壊れやすいテスト群になりがちです。 実務では、見るべき軸はもう少しはっきりしています。
- 確かめたいのは、自分たちのロジックか、外とのつなぎ込みか
- in-memory の fake で置き換えても、意味が落ちないか
- DB / ファイル / HTTP / DI / 設定 / フレームワーク / OS の挙動が本題か
- 大量の入力パターンを高速に回したいか
この 4 つが見えると、ユニットテストと結合テストの境界はかなり引きやすくなります。
この記事は、C# / .NET での自動テスト設計 を前提に書いています。コード例は xUnit ですが、判断基準そのものはフレームワークに依存しません。JUnit でも pytest でも、そのまま読み替えられる形にしてあります。
内容は 2026 年 3 月時点で参照できる、Microsoft Learn の「Integration tests in ASP.NET Core」1、同じく「Unit testing best practices for .NET」2、および Martin Fowler の「The Practical Test Pyramid」3 を前提にしています。以降、番号だけの参照にならないよう、本文中でも出典名を書いていきます。原典の URL は記事末の参考資料にまとめました。
1. まず結論
かなり雑に、でも実務で使いやすい言い方をすると、こうです。
- 純粋ロジックはユニットテスト
- 接続・配線・変換・環境差は結合テスト
- どちらでも検証できるなら、まずユニットテスト
- 結合テストは広く重くするより、境界を狭く絞る
ひとことで言えば、ユニットテストは「判断のテスト」、結合テストは「接続のテスト」です。
金額計算、状態遷移、入力検証、承認条件、例外の分類のように、外部資源なしで意味が完結するものは、ユニットテストへ寄せたほうが速く、壊れにくく、入力パターンも厚く回せます。 一方で、SQL の実行、JSON / CSV の直列化、ルーティング、モデルバインディング、DI 登録、ファイルロック、権限、COM 登録、32bit / 64bit、STA / MTA のような「つながった瞬間に裏切るもの」は、結合テスト側へ置いたほうが安全です。
Microsoft Learn の Integration tests in ASP.NET Core でも、統合テストは重要なインフラシナリオに絞り、ユニットテストで済むならそちらを選ぶよう整理されています。
この記事の知識マップ
ユニットテストと結合テストの境界を、判断のテストか接続のテストかという軸で整理する記事です。金額計算や状態遷移のような分岐の総当たりはユニットテストへ寄せ、フォーマット・配線・環境・時間という4つの境界はin-memoryのfakeでは意味が落ちるため結合テストへ置くべきだとします。stub・mock・fakeというテストダブルの違いを整理したうえで、mockが増えすぎる兆候は配線をユニットテストへ押し込んでいる合図であり、コア層をユニットテストで厚く、境界層を狭い結合テストで、全体層を少数のスモーク/E2Eで構成する3層構成を実務での落としどころとして示します。
flowchart LR
accTitle: ユニットテストと結合テストの境界の知識マップ
accDescr: ユニットテストが判断のテストで結合テストが接続のテストであること、フォーマット・配線・環境・時間という4つの境界が結合テスト側に置かれるべきこと、stub・mock・fakeの違いとmock過多が配線の混入を示す兆候であること、コア層・境界層・全体層からなる3層のテスト構成の関係を示す図
unit_test["ユニットテスト"]
integration_test["結合テスト"]
test_stub["スタブ"]
test_mock["モック"]
test_fake["フェイク"]
format_boundary["フォーマットの境界"]
wiring_boundary["配線の境界"]
environment_boundary["環境の境界"]
time_boundary["時間の境界"]
branching_coverage["分岐の総当たり"]
bitness_match_requirement["bitness一致要件"]
com_apartment_model["COMアパートメントモデル(STA/MTA)"]
mock_overuse_smell["mockが増えすぎる兆候"]
three_layer_test_structure["3層のテスト構成"]
e2e_test["E2Eテスト"]
unit_test -.->|"利用する"| test_stub
unit_test -.->|"利用する"| test_mock
unit_test -.->|"利用する"| test_fake
integration_test -->|"推奨される対応"| format_boundary
integration_test -->|"推奨される対応"| wiring_boundary
integration_test -->|"推奨される対応"| environment_boundary
integration_test -->|"推奨される対応"| time_boundary
unit_test -->|"推奨される対応"| branching_coverage
environment_boundary -.->|"前提とする"| bitness_match_requirement
environment_boundary -.->|"前提とする"| com_apartment_model
test_mock -.->|"原因になり得る"| mock_overuse_smell
unit_test -->|"用いるのは非推奨"| wiring_boundary
three_layer_test_structure -->|"前提とする"| unit_test
three_layer_test_structure -->|"前提とする"| integration_test
three_layer_test_structure -->|"前提とする"| e2e_test
integration_test -->|"用いるのは非推奨"| branching_coverage
test_fake -->|"用いるのは非推奨"| environment_boundary
test_fake -->|"用いるのは非推奨"| format_boundary
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全18件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. この記事でいうユニットテストと結合テスト
ここでは、用語をこう使い分けます。
| レベル | 何を確かめるか | 典型的な構成 |
|---|---|---|
| ユニットテスト | 分離された 1 責務の正しさ | fake / mock / stub を使い、外部資源を切る |
| 結合テスト | 複数コンポーネントの接続と、インフラやフレームワークを含む挙動 | 実 DB、実ファイル、実 serializer、実 host、実 pipeline など |
| E2E / 機能テスト | アプリ全体のユーザーフロー | デプロイ済みアプリ、複数サービス、実ブラウザや実プロセス |
.NET のユニットテスト整理では、よいユニットテストは fast / isolated / repeatable で、ファイルシステムや DB のような外部要因へ依存しないものとして説明されています。詳しくは Unit testing best practices for .NET が分かりやすいです。
また、結合テストは「別プロセスや別サーバーを必ず使う重いテスト」だけを指すわけではありません。 同一プロセス内でも、複数の実コンポーネントをつなぎ、フレームワークやインフラの本物の挙動を確かめるなら、それは結合テスト寄りです。
たとえば ASP.NET Core の controller action をユニットテストするとき、対象は action 本体の判断に絞り、routing、model binding、filters のようなフレームワーク側の相互作用は結合テストで扱う、という切り分けが公式にも示されています。詳しくは Unit test controller logic in ASP.NET Core を見ると整理しやすいです。
2.1. fake / mock / stub の区別
上の表で fake / mock / stub と並べましたが、この 3 つは同じものではありません。テストダブル(テスト用の代役)の分類として、この記事では次の意味で使います。Martin Fowler の「Mocks Aren’t Stubs」の整理に沿った使い分けです。4
| 呼び方 | 何をするものか | 典型的な使いどころ |
|---|---|---|
| stub | 決められた値を返すだけの代役。呼ばれ方は検証しない | 「在庫は常に 3 個」のように、入力条件を固定したいとき |
| mock | 呼ばれ方そのものを検証する代役。呼び出し回数や引数を assert する | 「保存が 1 回だけ呼ばれること」を確かめたいとき |
| fake | 本物と同じ振る舞いを、軽い実装で置き換えたもの | in-memory のリポジトリ、一時ディレクトリ上のファイル置き場など |
ざっくり言えば、stub は入力の代役、mock は呼び出しの検証、fake は簡易実装 です。 この区別が効いてくるのは 4 章です。「mock が 7 個いる」という兆候は、正確には 呼び出しの検証対象が 7 個ある ということで、そのテストが 1 つの判断ではなく、複数部品のつなぎ方を確かめようとしている合図になります。
2.2. E2E をこの記事でどう扱うか
この記事の主題は、あくまで ユニットテストと結合テストの境界 です。E2E / 機能テストは対比のために上の表へ入れていますが、本文では深く扱いません。
位置づけだけ確認しておくと、テストピラミッドの考え方では、下の層ほど本数が多くて速く、上の層ほど本数が少なくて遅い 三角形になります。Martin Fowler の「The Practical Test Pyramid」がこの整理の出発点です。3 つまり、ユニットテストを土台に、結合テストを境界ごとに置き、E2E は主要フローだけに絞る、という比率です。具体的な置き方は 7 章の 3 層構成にまとめました。
3. 一枚で見る判断表
まずは、いちばん実務で使いやすい表を置きます。
| 確かめたいもの | 主力にするテスト | 補足 |
|---|---|---|
| 金額計算、割引、状態遷移、入力検証 | ユニットテスト | 入力パターンを厚く回したい |
| 例外の分類、エラーメッセージ選択、リトライするかの判断 | ユニットテスト | 実 I/O なしで意味が完結する |
| Repository の SQL / ORM 変換、transaction | 結合テスト | 実 DB や実 provider の挙動が本題 |
| JSON / XML / CSV の serialize / deserialize | 結合テスト | wire format のズレは fake では見つけにくい |
| ルーティング、モデルバインディング、フィルター、middleware | 結合テスト | フレームワークとの接続確認 |
| WPF / WinForms の ViewModel や Presenter の状態遷移 | ユニットテスト | UI を立てなくても意味がある |
| 実際の Binding、Dispatcher、control lifecycle、message loop | 結合テスト or UI テスト | フレームワークとスレッドの挙動が主題 |
| ファイルパス、権限、ロック、共有フォルダ、改行コード、文字コード | 結合テスト | OS とファイルシステムの実挙動が必要 |
| COM 登録、32bit / 64bit、STA / MTA、DLL ロード | 結合テスト | 環境差とプロセス境界が主題 |
| アプリ全体の起動、主要ユースケースの通し確認 | E2E / スモーク | 本数は少なくてよい |
見方のコツは、どのテストが「本番で壊れる理由」にいちばん近いかです。 コードの置き場所ではなく、減らしたい不確実性で決めるほうがぶれません。
4. ユニットテストで持つべきもの
ユニットテストに向くのは、外界を取り去っても意味が残る責務です。
たとえばこんなものです。
- 業務ルール
- 分岐
- 状態遷移
- 入力検証
- エラー分類
- リトライ方針の決定
- ViewModel / Presenter の状態変化
- 変換ロジックそのもの
特に、組み合わせが多いものほどユニットテストへ寄せる価値が高いです。
たとえば、
- クーポンあり / なし
- 在庫あり / なし
- 初回注文 / 再注文
- 管理者 / 一般ユーザー
- 正常値 / 境界値 / 不正値
のように、分岐条件が増えるほど、結合テストで全部回すのは重くなります。 ここはユニットテストで細かく刻むほうが合理的です。
また、ユニットテストでは 外部要因を制御可能にしておく のが重要です。
- 現在時刻は注入する
- GUID や乱数は差し替えられるようにする
- sleep で待たない
- 実 DB や実ファイルに触れない
- 実ネットワークに出ない
このへんが守られると、テストはかなり安定します。
4.1. ユニットテストで mock が増えすぎるとき
ユニットテストを書こうとしたら、
- mock が 7 個いる
- setup が長い
- arrange が本体より長い
- 何を確認したいのか見えない
となるなら、たいてい次のどちらかです。
- そのクラスが責務過多
- 本当は結合テストで確かめるべき配線を、ユニットテストへ押し込んでいる
mock は外界を切るための道具であって、本物との接続が正しいことを証明する道具ではありません。 ここを取り違えると、「全部 green なのに本番で落ちる」が起きやすくなります。
4.2. ユニットテストの最小例
言葉だけだと抽象的になるので、境界の両側をコードで 1 本ずつ置いてみます。まずはユニットテスト側です。ViewModel の状態遷移は UI を立てなくても意味が完結するので、ここはユニットテストの領域です。
// .NET 8 / xUnit
// 対象: 外部資源にいっさい触らない ViewModel
public sealed class OrderViewModel
{
public decimal Subtotal { get; set; }
public bool IsMember { get; set; }
public bool CanCheckout => Subtotal > 0m;
public decimal Total => IsMember ? Subtotal * 0.9m : Subtotal;
}
public class OrderViewModelTests
{
[Fact]
public void 会員なら1割引きになる()
{
var viewModel = new OrderViewModel { Subtotal = 1000m, IsMember = true };
Assert.Equal(900m, viewModel.Total);
}
[Theory]
[InlineData(0, false)]
[InlineData(1, true)]
public void 小計が0なら確定できない(int subtotal, bool expected)
{
var viewModel = new OrderViewModel { Subtotal = subtotal };
Assert.Equal(expected, viewModel.CanCheckout);
}
}
ここには DB もファイルも HTTP も出てきません。だから速く、並列に回せて、[Theory] で入力パターンをいくらでも増やせます。
分岐の総当たりをここへ寄せる というのは、具体的にはこの形のことです。
5. 結合テストへ上げる 4 つの境界
結合テストへ上げるべき場所は、だいたい フォーマット、配線、環境、時間 の 4 つに整理できます。
5.1. フォーマットの境界
ここでいうフォーマットには、こんなものが入ります。
- JSON / XML / CSV
- DB の schema と mapping
- nullable / precision / timezone
- enum や日付のシリアライズ
- 文字コードや BOM
- 改行コード
Martin Fowler も、serialize / deserialize が入る境界は結合テスト候補として挙げています。詳しくは The Practical Test Pyramid が参考になります。
たとえば、
- DTO を JSON にしたらフィールド名が違った
- CSV の引用符や改行が壊れた
decimalが丸められた- DB で
DateTimeOffsetの扱いがずれた nullと空文字の扱いが想定と違った
のような不具合は、ユニットテストだけでは抜けやすいです。
5.2. 配線の境界
配線の境界に入るのは、たとえばこういう部分です。
- DI 登録
- 設定の bind
- ルーティング
- モデルバインディング
- フィルター
- middleware
- host の起動
- イベント配線
- WPF の Binding や command 接続
ここは「自分の関数が正しいか」ではなく、複数の実部品が正しくつながっているか が本題です。
ASP.NET Core では、controller action のユニットテストは action の判断へ絞り、routing や model binding、filters は結合テスト側で見る整理が公式にあります。
Web でなくても考え方は同じで、デスクトップアプリでも、ViewModel の状態遷移はユニットテスト、実際の XAML Binding や Dispatcher を含む挙動は結合テスト寄りです。
5.3. 環境の境界
Windows 開発では、ここがかなり重要です。
- ファイル権限
- 共有フォルダ
- ファイルロック
- 一時ファイルからの rename
- 管理者権限
- サービス起動権限
- COM 登録
- 32bit / 64bit
- STA / MTA
- DLL のロード元
このへんは、OS や実行環境の条件そのもの が主役です。 in-memory fake では意味がかなり落ちるので、結合テストで押さえたほうが安全です。
特に、既存 Windows ソフトや COM / ActiveX を含む構成では、ロジックより先に 登録、bitness、スレッドモデル、権限 で転ぶことが普通にあります。 こういう失敗は、ユニットテストではなく、環境を含めた結合テストが拾う領域です。
5.4. 時間の境界
もうひとつ見落としやすいのが、時間と並行性です。
- timeout
- cancellation
- retry の実挙動
- timer 駆動
- バックグラウンド処理の停止
- race condition
- shutdown 時の終了順序
ここで大事なのは、判断と実挙動を分ける ことです。
たとえば、
- 何回まで retry するか
- どの例外を retry 対象にするか
はユニットテストで十分です。 一方で、
- 実際に timeout が効くか
- cancellation が伝播するか
- timer と非同期処理がぶつかったときに壊れないか
- 終了時にハンドルやタスクがきれいに閉じるか
は結合テスト寄りです。
5.5. 結合テストの最小例
4.2 と同じ題材で、境界のもう一方を書いてみます。ここで確かめたいのは「保存した金額が、DB を往復しても壊れないか」です。実際の SQLite ファイルを通します。
// .NET 8 / xUnit / Microsoft.Data.Sqlite
using System.Globalization;
using Microsoft.Data.Sqlite;
public sealed class OrderRepository(SqliteConnection connection)
{
public void Save(int id, decimal total)
{
using var command = connection.CreateCommand();
command.CommandText = "INSERT INTO orders (id, total) VALUES ($id, $total);";
command.Parameters.AddWithValue("$id", id);
command.Parameters.AddWithValue("$total", total.ToString(CultureInfo.InvariantCulture));
command.ExecuteNonQuery();
}
public decimal FindTotal(int id)
{
using var command = connection.CreateCommand();
command.CommandText = "SELECT total FROM orders WHERE id = $id;";
command.Parameters.AddWithValue("$id", id);
var stored = (string)command.ExecuteScalar()!;
return decimal.Parse(stored, CultureInfo.InvariantCulture);
}
}
public sealed class OrderRepositoryTests : IDisposable
{
private readonly string _databasePath =
Path.Combine(Path.GetTempPath(), $"orders-{Guid.NewGuid():N}.db");
private readonly SqliteConnection _connection;
public OrderRepositoryTests()
{
// Pooling=False にしておかないと、後始末で db ファイルを消せないことがあります
_connection = new SqliteConnection($"Data Source={_databasePath};Pooling=False");
_connection.Open();
using var create = _connection.CreateCommand();
create.CommandText = "CREATE TABLE orders (id INTEGER PRIMARY KEY, total TEXT NOT NULL);";
create.ExecuteNonQuery();
}
[Fact]
public void 保存した金額が丸められずに読み戻せる()
{
var repository = new OrderRepository(_connection);
repository.Save(id: 1, total: 1234.56m);
Assert.Equal(1234.56m, repository.FindTotal(1));
}
public void Dispose()
{
_connection.Dispose();
File.Delete(_databasePath);
}
}
このテストが確かめているのは、OrderRepository の分岐ではありません。SQL が通るか、列の型と decimal の対応が合っているか、往復して値が保たれるか という接続の部分です。SQLite には decimal 型がないので、「どの型で保存すれば往復しても壊れないか」は実装の問題ではなく 接続の設計 の問題になります。ここは in-memory の fake では見えません。
この例では、テストクラスごとに一時 DB ファイルを 1 つ作り、Dispose で消しています。結合テストは状態を持つので、どこで作ってどこで捨てるかを毎回はっきりさせる ことが、ユニットテストより重要になります。
6. よくある判断ミス
6.1. Repository を mock して満足してしまう
Repository まわりを全部 mock で通しても、
- SQL が正しいか
- transaction が効くか
- schema と一致しているか
- mapping がずれないか
- 文字コードや precision が壊れないか
は分かりません。
Repository は、ロジックのテスト対象というより、境界の接続点であることが多いです。 その場合はユニットテストより、結合テストの比重を上げたほうが実態に合います。
6.2. Controller / Endpoint のユニットテストでフレームワークまで見ようとする
controller action のユニットテストで見たいのは、
- 条件分岐
- 戻り値の選択
- 依存サービスの呼び分け
あたりです。
一方で、
- route が当たるか
- model binding が通るか
- filter が効くか
- middleware を通した結果どう見えるか
は結合テスト側です。 ここを混ぜると、何が壊れたのか分かりにくくなります。
6.3. 結合テストで入力パターンを総当たりする
結合テストは本物に近いぶん、どうしても遅くなります。 だから、分岐の総当たりはユニットテスト、境界の代表ケースは結合テスト と分けたほうが得です。
Microsoft Learn の統合テスト解説でも、DB やファイルシステムに対しては全パターンを結合テストで回すのではなく、read / write / update / delete のような代表的なシナリオへ絞る 方向が勧められています。
6.4. CI から外部サービスの本番系をそのまま叩く
これは避けたほうが安全です。
結合テストは「本物らしさ」が大事ですが、だからといって毎回本番 SaaS や本番 API を叩く必要はありません。 Fowler も、外部サービスはローカルに立てる、fake を置く、もしくは専用の test instance を使う方向を勧めています。
実務では、
- ローカル DB
- 一時ディレクトリ
- test host
- 専用の test environment
- 契約を固定した fake service
の組み合わせが扱いやすいです。
7. 実務でのおすすめ構成
比率に絶対の正解はありません。 ただし、かなり汎用的に使えるのは、次の 3 層です。
| 層 | 主力 | 何を置くか |
|---|---|---|
| コア層 | ユニットテストを厚く | 業務ルール、状態遷移、入力検証、エラー分類 |
| 境界層 | 狭い結合テストを置く | DB、ファイル、HTTP、serializer、DI、設定、COM、権限 |
| 全体層 | 少数のスモーク / E2E | 起動確認、主要フロー、重大障害の再発防止 |
感覚的には、数で厚くなるのはユニットテスト、境界の濃さで厚くなるのが結合テスト です。
おすすめの進め方はこうです。
- まず、アプリの境界を列挙する
- ロジックを外界から切れる形に寄せる
- 境界ごとに「最低 1 本の happy path」と「代表的な failure path」を置く
- 全体の通しは本数を絞る
- バグが出たら、そのバグを最小コストで再現できる層へテストを追加する
最後の 5 が大事です。
- ルールの誤りなら、ユニットテストを追加する
- SQL / binding / 設定 / 権限 / 登録の誤りなら、結合テストを追加する
- 起動や配布を含む障害なら、スモークや E2E を追加する
この増やし方をすると、テストの責務がぶれにくくなります。
8. 迷ったときに最後に見る 5 問
最後に、迷ったときのチェック用に 5 問へまとめます。
- in-memory の fake で置き換えても、確認したい意味は残るか
- 残るなら、ユニットテスト寄りです。
- 壊れたときに疑うのは、ロジックではなく接続や設定ではないか
- そうなら、結合テスト寄りです。
- DB / ファイル / serializer / DI / route / model binding / OS / 権限 / bitness / thread が主題ではないか
- そうなら、結合テスト寄りです。
- 大量の入力パターンを高速に回したいか
- そうなら、ユニットテスト寄りです。
- そのテストが落ちたとき、何を直せばよいかがすぐ分かるか
- 分からないなら、テストの層が混ざっています。
この 5 問で整理すると、「何となく本物に近いから結合テスト」「何となく速いからユニットテスト」という雑な決め方を避けやすくなります。
9. まとめ
ユニットテストと結合テストの境界は、コードの置き場所ではなく、何の不確実性を減らしたいか で決めるのがいちばん実務的です。
要点はこの 5 つに尽きます。
- ユニットテストは判断のテスト
- 結合テストは接続のテスト
- 分岐の総当たりはユニットテスト
- フォーマット、配線、環境、時間は結合テスト
- 全体の通し確認は少数のスモーク / E2E で押さえる
いちばん避けたいのは、
- mock で本物との接続まで証明した気になる
- 結合テストで全部の分岐を回そうとする
- ユニットテストと結合テストの責務を混ぜる
の 3 つです。
迷ったら、その不具合は「判断」が壊れるのか、「接続」が壊れるのか を先に見てください。 この 1 問で、かなりのケースは整理できます。
10. 関連記事
- Windowsアプリ開発における最低限のセキュリティを守るためのチェックリスト
- Windows アプリを本当にシングルバイナリにできる範囲はどこまでか
- Windows の管理者特権が必要になるのはいつなのか
- Reg-Free COM とは何か
11. 参考資料
-
Microsoft Learn, Integration tests in ASP.NET Core ↩
-
Microsoft Learn, Unit testing best practices for .NET ↩
-
Martin Fowler, The Practical Test Pyramid ↩ ↩2
-
Martin Fowler, Mocks Aren’t Stubs ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
Windows Sandboxでアプリ検証を速くする方法
Windows Sandbox を使って、管理者権限の問題の切り分け、クリーン環境での再現、権限不足・リソース不足の再現を効率化する方法を、.wsb と CLI の使い分けまで含めて整理します。
想定外例外で終了すべきか継続すべきかの判断表
想定していない例外が起きたときに、アプリを終了させるべきか継続すべきかを、状態破壊・外部副作用・スレッド・ネイティブ境界の観点から整理します。
Windowsアプリで「管理者権限が必要な処理だけ」を分離する具体的な書き方
Windows アプリで UI を asInvoker のまま保ちつつ、管理者権限が必要な処理だけを helper EXE に分離する設計を、UAC、runas、名前付きパイプ、入力検証まで含めて具体的に整理します。
Windowsアプリの機密情報保存 - DPAPIで平文設定を避ける
Windows アプリで接続情報や API トークンを設定ファイルに平文保存しないために、DPAPI / ProtectedData の考え方、CurrentUser と LocalMachine の違い、実装時の注意点を整理します。
Windowsアプリ開発のセキュリティ最低限チェックリスト
WPF / WinForms / WinUI / C++ / C# の業務アプリで、権限、署名、更新、秘密情報、HTTPS、入力検証、DLL読み込み、ログの基本をチェックリスト形式で整理します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
技術相談・設計レビュー
ユニットテストと結合テストの境界をどこで切るかは、実装前の設計レビューやテスト戦略の相談として整理しやすいからです。
Windowsアプリ開発
Windows アプリではファイル、権限、COM、32bit / 64bit などの境界がテスト層にも直結するため、実装方針の整理と相性がよいからです。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- ユニットテストと結合テストはどう使い分ければよいですか?
- ひとことで言えば、ユニットテストは「判断のテスト」、結合テストは「接続のテスト」です。金額計算、状態遷移、入力検証、例外の分類のように外部資源なしで意味が完結するものはユニットテストへ寄せ、SQLの実行、JSON/CSVの直列化、ルーティング、DI登録、ファイルロック、権限、COM登録、32bit/64bitのような「つながった瞬間に裏切るもの」は結合テスト側へ置きます。どちらでも検証できるなら、まずユニットテストです。
- どんなものを結合テストへ上げるべきですか?
- だいたいフォーマット、配線、環境、時間の4つの境界に整理できます。フォーマットはJSON/CSVやDBのmapping、文字コードなど、配線はDI登録、ルーティング、モデルバインディングなどの実部品のつなぎ込み、環境はファイル権限、COM登録、32bit/64bit、STA/MTAなどOSの実挙動、時間はtimeout、cancellation、race conditionなどです。これらはin-memoryのfakeでは意味が落ちるため、結合テストで押さえたほうが安全です。
- ユニットテストでmockが増えすぎるのは何が問題ですか?
- mockが7個いる、setupが長い、何を確認したいのか見えない、という状態なら、そのクラスが責務過多か、本当は結合テストで確かめるべき配線をユニットテストへ押し込んでいるかのどちらかです。mockは外界を切るための道具であって、本物との接続が正しいことを証明する道具ではありません。ここを取り違えると「全部greenなのに本番で落ちる」が起きやすくなります。
- テストはどんな構成・比率で持つのがよいですか?
- 汎用的に使えるのは3層構成です。コア層は業務ルールや状態遷移をユニットテストで厚く持ち、境界層はDB・ファイル・serializer・DIなどに狭い結合テストを置き、全体層は起動確認や主要フローを少数のスモーク/E2Eで押さえます。分岐の総当たりはユニットテストで回し、結合テストは境界ごとに最低1本のhappy pathと代表的なfailure pathへ絞ります。バグが出たら、そのバグを最小コストで再現できる層へテストを追加します。