LASSIC Media らしくメディア
単体テストと結合テストの違い|範囲・目的・担当の分け方
監修・編集責任者:牛尾 昭昌(株式会社LASSIC 執行役員)
この記事の結論
- 単体テストは部品1つを依存先から切り離して確かめ、結合テストは部品どうしのつなぎ目を本物に近い相手とつないで確かめます。
- 単体テストは書いた開発者が手元ですぐ直し、結合テストは欠陥を記録して、つないだ双方の担当者で原因を絞り込みます。
- 結合テストで部品の中身を繰り返し確かめず、つなぎ目の値の意味・単位・順序に絞ると、2つの違いが実務で生きます。
※ 本記事は2026年10月時点の公式情報(省庁・公的機関、および製品やサービスを提供する事業者が公開している資料)に基づきます。
単体テストと結合テストの違いは、一度に確かめる範囲と、そこで見つけたい欠陥の種類にあります。単体テストは関数やクラスといった部品を1つだけ取り出して確かめ、結合テストは部品どうしをつないで、受け渡しが設計どおりかを確かめます。単体テストはすべて通ったのに、画面から操作すると金額が10倍になった——。こうした不具合は、部品の中ではなく部品のあいだで起きています。
本記事では、ISTQB(国際ソフトウェアテスト資格認定委員会)のシラバスの日本語版と、pytest・Maven の公式ドキュメントをもとに、範囲・目的・担当・環境・合否基準・欠陥の見つかり方の6つの観点で違いを整理します。Pythonのコード例では、同じ計算を2つのテストで確かめると何が起きるかを示します。テスト計画の立て方全体や受入テストは、それぞれの記事にお任せします。
目次
単体テストと結合テストとは
JSTQB(日本ソフトウェアテスト資格認定委員会)が公開しているFoundation Levelシラバス(Version 2023V4.0.J02)は、単体テストに当たるものを「コンポーネントテスト(ユニットテストとも呼ばれる)」と呼び、「コンポーネントを単独でテストすること」に焦点を当てるとしています。*1 コンポーネントとは、関数やクラス、モジュールのように、ひとまとまりで扱える部品のことです。
結合テストは、シラバスでは統合テストと呼ばれ、コンポーネント統合テストとシステム統合テストの2つのレベルに分かれています。コンポーネント統合テストは「コンポーネント間のインターフェース、および相互処理」に、システム統合テストは、テスト対象のシステムとほかのシステムや外部サービスとのインターフェースに焦点を当てます。*1 日本の現場で「結合テスト」と呼ぶ作業には、この2つが混ざっていることがよくあります。呼び名の食い違いと体制の決め方は「外部エンジニアと進める結合テスト、テスト体制に書く4つの役割」で扱っています。
同じシラバスは、テストレベルを区別する属性として、テスト対象、テスト目的、テストベース、欠陥および故障、アプローチと責務の5つを挙げています。*1 テストベースとは、何が正しいかを判断するよりどころになる文書やコードのことです。本記事の比較も、この区別に沿って進めます。システムテストや受入テストを含めたテストレベル全体の位置づけは「テスト計画・テスト設計の外注」にまとめています。
範囲と目的の違い
範囲の違いは、依存先をどう扱うかに表れます。前の版のシラバス(Version 2018V3.1.J03)は、コンポーネントテストではシステムのほかの部分と切り離したテストが可能な場合が多く、その際にモックオブジェクト、サービス仮想化、ハーネス、スタブ、ドライバーなどを使うと説明しています。*2 データベースや外部APIを代役に置き換え、部品の中身だけに注目できるようにするわけです。代役の種類と使い分けは「テストダブルとは」で解説しています。
結合テストでは、代役を外して本物、または本物に近いものをつなぎます。同じシラバスは、統合テストの目的として、インターフェースの機能的・非機能的な振る舞いが設計および仕様どおりであることの検証を挙げています。*2 単体テストの目的が部品の振る舞いの検証であるのに対し、結合テストが見るのは受け渡しの部分です。
範囲を広げすぎないことも大切です。シラバスは、モジュールAとBの統合をテストするときは、コンポーネントテストで確かめ済みの個々の機能ではなく、2つのモジュール間のコミュニケーションに焦点を当てるべきだとしています。結合テストで計算の細かな場合分けまで繰り返すと、手間が増えるわりに、新しく分かることはあまりありません。
担当と環境の違い
単体テストの担当は、多くの場合そのコードを書いた開発者です。v4.0のシラバスは、コンポーネントテストは通常、開発担当者が開発環境で行うとしています。*1 v3.1のシラバスは、開発者以外が行う場合でも、少なくともテスト対象のコードにアクセスできる必要があると付け加えています。コードを見ずに行う単体テストは成り立ちにくい、ということです。
結合テストの担当は、つなぐ範囲で変わります。v3.1のシラバスでは、コンポーネント統合テストは開発担当者が、システム統合テストはテスト担当者が行うのが一般的とされています。システムどうしをつなぐテストでは、相手のシステムの持ち主とも日程や環境を合わせることになります。
環境の違いも大きなポイントです。単体テストは代役を使うため、開発者の手元とCI(継続的インテグレーション)の両方で同じように動かせます。結合テストでは、データベースや外部のサービスを用意しなければなりません。v4.0のシラバスは、システム統合テストには、できれば運用環境に近い適切なテスト環境が必要になるとしています。*1 部品どうしの結合テストでは、コンテナで使い捨てのデータベースを立ち上げる方法もあります。その進め方は「Testcontainersで統合テストを外注で進める」をご覧ください。
合否基準と欠陥の見つかり方
1件ずつのテストの合否は、どちらも期待結果と実際の結果が一致するかで決まります。違いが出るのは、そのテストレベルを終えてよいかを決める基準です。v4.0のシラバスは、シーケンシャルな開発モデルでは、あるレベルの終了基準が次のレベルの開始基準の一部になるように定めることが多いとしています。*1 例えば「単体テストがすべて通り、決めた網羅率を満たしていること」を、結合テストを始める条件にします。網羅率の測り方とCIへの組み込みは「テストカバレッジ計測とゲート導入を外注する要点」で扱っています。
見つかる欠陥の種類も違います。v3.1のシラバスは、コンポーネントテストの典型的な欠陥として、正しくない機能、データフローの問題、正しくないコードとロジックを挙げています。*2 コンポーネント統合テストの典型としては、正しくないデータやデータ不足、インターフェース呼び出しの順序やタイミングの誤り、インターフェースの不整合、コンポーネント間で渡されるデータの意味・単位・境界についての正しくない思い込みなどを挙げています。
| 観点 | 単体テスト | 結合テスト |
|---|---|---|
| 範囲 | 関数・クラス・モジュールなど部品1つ | 部品と部品、部品とDBや外部APIとのつなぎ目 |
| 目的 | 部品が設計どおりに動くことを確かめる | インターフェースが設計どおりに動くことを確かめる |
| よりどころ | 詳細設計・コード・コンポーネント仕様 | システム設計・シーケンス図・インターフェース仕様 |
| 担当 | コードを書いた開発者 | 部品どうしは開発者、システムどうしはテスト担当者が多い |
| 依存先 | スタブやモックなどの代役に置き換える | 本物、または本物に近いものをつなぐ |
| 見つかる欠陥 | 計算・分岐・データの流れの誤り | データの形・単位・呼び出し順序・通信の食い違い |
欠陥の扱い方にも差があります。単体テストで見つけた欠陥は、形式に沿った管理をせず、見つけたらすぐに直すのが一般的とされています。*2 一方で、統合の範囲が大きくなるほど、欠陥を特定のコンポーネントに絞り込むのは難しくなります。そのためシラバスは、すべてを一度につなぐビッグバンではなく、少しずつつなぐインクリメンタルな統合を普通のやり方としています。
具体例:同じ計算を2通りで確かめる
税込み金額を計算する関数を例にします。税率は別の部品から受け取ります。単体テストでは、税率を返す部品をスタブに置き換えます。
# price.py
def total_with_tax(subtotal, rate_source):
rate = rate_source.tax_rate() # 0.10 のような小数を受け取る前提
return round(subtotal * (1 + rate))
# test_price.py(単体テスト)
from price import total_with_tax
class StubRate: # 依存先の代役(スタブ)
def tax_rate(self):
return 0.10
def test_total_with_tax():
assert total_with_tax(1000, StubRate()) == 1100
このテストは通ります。関数の中の計算に誤りはありません。次に、税率をデータベースから読む部品とつないで結合テストを書きます。Pythonの標準ライブラリのsqlite3は、接続先に”:memory:”を渡すと、メモリ上にだけ存在するデータベースを作れます。*3 テストのたびに作って捨てられるので、結合テストの練習台に向いています。
# rate_repo.py
class RateRepo:
def __init__(self, con):
self.con = con
def tax_rate(self):
sql = "SELECT rate FROM tax WHERE code = 'std'"
return self.con.execute(sql).fetchone()[0] # 表には 10(%)で入っている
# test_price_integration.py(結合テスト)
import sqlite3
import pytest
from price import total_with_tax
from rate_repo import RateRepo
@pytest.mark.integration
def test_total_with_tax_via_db():
con = sqlite3.connect(":memory:")
con.execute("CREATE TABLE tax (code TEXT, rate REAL)")
con.execute("INSERT INTO tax VALUES ('std', 10)")
assert total_with_tax(1000, RateRepo(con)) == 1100 # 11000 が返り失敗する
こちらは失敗し、1100ではなく11000が返ります。関数は税率を0.10のような小数で受け取る前提で書かれていますが、表には10(パーセント)で入っていたからです。部品それぞれは設計どおりに動いていても、あいだで受け渡す値の単位の思い込みが食い違っています。シラバスが統合テストの典型的な欠陥に挙げる「意味、単位、境界の正しくない思い込み」そのものです。*2 直し方は、どちらか一方のコードを変える前に、インターフェースの仕様で税率の形を決めることです。
単体テストのスタブが返す値を、仕様ではなく書き手の思い込みで決めていたことも、見落としの原因になりました。スタブの値は、つなぐ相手の仕様書から取るのが基本です。どの値を選べば少ないテストで漏れを減らせるかは、同値分割や境界値分析といった技法の出番になります。
使いどころ:CIでの分け方
実務では、単体テストと結合テストを別々のタイミングで動かせるようにしておくと便利です。pytestでは、テストに目印(マーカー)を付け、コマンドラインの-mオプションで選んで実行できます。*4 自分で決めたマーカーは設定ファイルに登録しておきます。登録していないマーカーを使うと警告が出て、strict_markersを設定するとエラーになります。マーカー名のつづりの誤りで、結合テストが選ばれないまま見落とされる事故を防げます。
# pytest.ini
[pytest]
markers =
integration: DBなど本物の依存先とつなぐ結合テスト
strict_markers = true
# プルリクエストごと:単体テストだけ
pytest -m "not integration"
# マージ前:DBを用意して結合テストだけ
pytest -m integration
JavaとMavenの組み合わせでは、ビルドの道具自体が2つを分けています。Maven Failsafe Pluginは結合テストを、Surefire Pluginは単体テストを動かすために作られています。*5 既定では、Surefireは名前が「Test」で終わるクラスなどを、Failsafeは「IT」で終わるクラスなどを対象にします。*6 Failsafeは結合テストのフェーズでビルドを止めないため、そのあとの後片付けのフェーズが実行され、テスト環境を片付けられます。
速く動く単体テストを多く、準備の要る結合テストを少なめに積む考え方は、テストピラミッドと呼ばれます。どの比率が合うかはシステムの作りで変わるため、ここでは深入りしません。
つまずきやすい点
- 代役を使いすぎた単体テスト:依存先をすべてスタブにすると、テストが確かめているのはスタブの動きだけになりがちです。つなぎ目の確認は結合テストに残します
- 結合テストでの確かめ直し:部品の中の場合分けを結合テストで繰り返すと、失敗したときに原因の場所が分かりにくくなります
- 一度につなぐ結合:すべての部品をそろえてから一気につなぐと、失敗の原因を絞るのに時間がかかります
- 共有の環境で動かす結合テスト:ほかの人のデータが残っていると結果が毎回変わります。テストごとにデータを作り、終わったら片付けます
内部の構造を見て作るか、仕様だけを見て作るかという観点は、テストレベルとは別の軸です。単体テストでもブラックボックスの技法は使えますし、結合テストでも分岐の網羅を測れます。この軸の違いは「ホワイトボックステストとブラックボックステストの違い」で説明しています。
なお、v3.1のシラバスは、アジャイル開発ではアプリケーションのコードより先に、自動化されたコンポーネントのテストケースを書く場合があるとしています。これがテスト駆動開発の出発点です。単体テストをいつ書くかという話は、範囲の違いとは切り離して考えます。
外部に委託するときに確認しておきたい点
開発を外部に委託するときは、単体テストと結合テストのそれぞれについて、どこまでを誰が行い、何を成果として受け取るかを決めておきます。とくに次の点は、契約や作業の範囲を書く段階で確かめておくと食い違いを防げます。
- 単体テストの成果物:テストコードそのものを納品に含めるか、実行結果と網羅率の報告だけにするか
- 結合テストの範囲:部品どうしまでか、社内の既存システムや外部サービスとの接続まで含むか
- テスト環境:データベースや外部APIの検証環境を、発注側と受託側のどちらが用意するか
- インターフェースの仕様:値の単位・形式・文字コードを、どの文書で決めて誰が更新するか
- 欠陥の記録:結合テストで見つけた欠陥を、どの道具にどの項目で記録し、再テストを誰が行うか
単体テストのコードを成果物として受け取っておくと、保守を引き継いだあとも回帰テストとして使い続けられます。完成したシステムを発注側が確かめる受入テストの進め方は「システム開発の検収・受入テストの進め方」をご覧ください。
まとめ:単体テストと結合テストで確かめておきたい3つの点
単体テストと結合テストの違いを実務に生かすうえで、確かめておきたい点は3つです。第一に、単体テストは部品1つを代役で切り離して中身を確かめ、結合テストはつなぎ目を本物に近い相手とつないで確かめるという範囲の線を、チームで同じ位置に引くこと。第二に、担当・環境・終了基準をテストレベルごとに決め、単体テストの終了を結合テストの開始条件にしておくこと。第三に、結合テストではつなぎ目で受け渡す値の意味・単位・順序に焦点を絞り、インターフェースの仕様を文書で決めてから両側のコードとテストを書くことです。
よくある質問
単体テストとユニットテストは同じものですか
同じものです。JSTQBのシラバスは、コンポーネントテストをユニットテストとも呼ばれるとしています。会社によってはモジュールテストと呼ぶこともあります。
結合テストと統合テストは違うものですか
英語のintegration testingの訳し方の違いで、指すものは同じです。ただし、部品どうしをつなぐ段階だけを指す場合と、ほかのシステムとの接続まで含める場合があるため、範囲は文書で確かめます。
単体テストでデータベースにつないではいけませんか
禁止されているわけではありません。ただ、データベースにつなぐと、そのテストが確かめるのは部品とデータベースのつなぎ目になり、性格は結合テストに近づきます。準備と実行に時間がかかるため、目印を付けて分けて動かすと扱いやすくなります。
テストの設計と自動化のご相談
元請(プライムベンダー)として、単体テストと結合テストの分け方の設計から自動化、保守・運用までご提案します。
Remoguとリラシクなら、テストの自動化やシステムの保守・運用に加わるITエンジニアも探せます。
Remoguは、リモート前提で全国から即戦力のITプロ人材を調達するサービスです。リラシクは、扱う求人がすべてリモートワークのITエンジニア専門転職エージェントです。どちらもLASSICが運営しています。
出典
- *1 参考:JSTQB(日本ソフトウェアテスト資格認定委員会)「テスト技術者資格制度 Foundation Levelシラバス Version 2023V4.0.J02」(https://jstqb.jp/dl/JSTQB-SyllabusFoundation_VersionV40.J02.pdf)。出典:2.2(テストレベルとテストタイプ)、2.2.1(テストレベル:コンポーネントテスト・コンポーネント統合テスト・システム統合テストの説明と、テストレベルを区別する属性)を参照(2026年10月確認)
- *2 参考:JSTQB「テスト技術者資格制度 Foundation Levelシラバス Version 2018V3.1.J03」(2021年5月12日)(https://jstqb.jp/dl/JSTQB-SyllabusFoundation_Version2018V31.J03.pdf)。出典:2.2.1(コンポーネントテスト)、2.2.2(統合テスト)の目的・典型的な欠陥と故障・アプローチと責務を参照。現行のv4.0では簡略化された記述の詳細として参照(2026年10月確認)
- *3 参考:Python Software Foundation「sqlite3 — DB-API 2.0 interface for SQLite databases」(https://docs.python.org/3/library/sqlite3.html)。出典:”:memory:” を渡してメモリ上だけのデータベースを作る説明を参照(2026年10月確認)
- *4 参考:pytest「How to mark test functions with attributes」(https://docs.pytest.org/en/stable/how-to/mark.html)。出典:-m オプションでの選択、Registering marks、Raising errors on unknown marks(strict_markers)を参照(2026年10月確認)
- *5 参考:Apache Maven Project「Maven Failsafe Plugin – Introduction」(https://maven.apache.org/surefire/maven-failsafe-plugin/)。出典:Failsafe は結合テスト、Surefire は単体テストのために作られている点、integration-test フェーズでビルドを止めず post-integration-test を実行できる点を参照(2026年10月確認)
- *6 参考:Apache Maven Project「Inclusions and Exclusions of Tests」(Failsafe/Surefire)(https://maven.apache.org/surefire/maven-failsafe-plugin/examples/inclusion-exclusion.html)。出典:Failsafe の既定の対象(**/IT*.java、**/*IT.java、**/*ITCase.java)を参照。Surefire の既定(**/*Test.java など)は https://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html を参照(2026年10月確認)