結合テストって何?単体テストとの違いからつかむ
結合テスト(integration test)は、
「複数の部品(関数・クラス・モジュール)を“つなげた状態”で、ちゃんと一緒に動くかを確認するテスト」です。
単体テストは「1 個の関数が正しいか」を見るテストでした。
結合テストは、「その関数たちを組み合わせた“流れ全体”が正しいか」を見るテストです。
もう少し具体的に言うと、
DB に保存する処理
保存したデータを読み出す処理
それを API レスポンスとして返す処理
などを「まとめて」動かして、「全体として期待どおりか?」を確認するのが結合テストです。
例題のシナリオを決める:シンプルな「ユーザー登録」
想定する流れ
初心者でもイメージしやすいように、
「ユーザー登録」の流れを例にします。
メールアドレスと名前を受け取る
DB にユーザーを保存する
保存したユーザーを DB から読み出す
読み出した結果を返す
この一連の流れが「ちゃんとつながっているか?」を確認するのが結合テストです。
ここでは、SQLite と SQLAlchemy を使った、かなり小さな例で考えます。
コード例:ユーザー登録の処理を分解して書く
モデルと DB セットアップ
# models.py
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.orm import declarative_base, sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, autoincrement=True)
email = Column(String, nullable=False, unique=True)
name = Column(String, nullable=False)
def create_engine_and_session(db_url: str = "sqlite:///:memory:"):
engine = create_engine(db_url)
Base.metadata.create_all(engine)
SessionLocal = sessionmaker(bind=engine)
return engine, SessionLocal
Pythonここでは、
ユーザーテーブルの定義
メモリ上の SQLite(sqlite:///:memory:)を使うエンジンとセッションの作成
までを用意しています。
アプリ側のロジック(サービス層)
# service.py
from sqlalchemy.orm import Session
from models import User
def create_user(session: Session, email: str, name: str) -> User:
user = User(email=email, name=name)
session.add(user)
session.commit()
session.refresh(user)
return user
def get_user_by_email(session: Session, email: str) -> User | None:
return session.query(User).filter_by(email=email).first()
Pythonここでは、
ユーザーを作って DB に保存する関数
メールアドレスでユーザーを検索する関数
を定義しています。
単体テストなら、create_user や get_user_by_email を
それぞれ個別に、DB を mock にしてテストすることもできます。
結合テストでは、「本物の SQLite を使って、これらを“つなげて”動かす」ことをやります。
結合テストを書く:流れ全体を確認する
pytest での結合テスト例
# test_integration_user.py
from models import create_engine_and_session
from service import create_user, get_user_by_email
def test_create_and_get_user():
engine, SessionLocal = create_engine_and_session()
session = SessionLocal()
created = create_user(session, "taro@example.com", "Taro")
fetched = get_user_by_email(session, "taro@example.com")
assert fetched is not None
assert fetched.id == created.id
assert fetched.email == "taro@example.com"
assert fetched.name == "Taro"
Pythonここでやっていることは、まさに「結合」です。
実際の DB(テスト用の SQLite)を立ち上げる
その DB に対して create_user で保存する
同じ DB に対して get_user_by_email で読み出す
「保存したものがちゃんと読めるか」を確認する
単体テストでは「関数単体のロジック」を見ていましたが、
結合テストでは「DB・モデル・サービス関数がつながったときに、全体として期待どおりか」を見ています。
結合テストで特に大事なポイント
「本物に近い環境」で動かすこと
結合テストの価値は、「実際の動きに近い形でテストできること」です。
本物の DB を使う(ただしテスト用のインスタンスやメモリ DB)
本物の ORM(SQLAlchemy など)を使う
本物の HTTP ルーティング(FastAPI や Flask のテストクライアント)を使う
など、「単体テストでは mock にしていた部分」を、
結合テストではあえて本物に近づけます。
その代わり、
テスト用の DB(本番とは別)
テスト用の設定(API キーや URL を変える)
を使って、「本番に影響を与えない」ようにします。
「流れ」と「つながり」をテストする意識
結合テストで確認したいのは、主に次のようなことです。
保存したデータが、別の処理からちゃんと読めるか
API のエンドポイントにリクエストを送ると、DB を経由して正しいレスポンスが返るか
トランザクションの境界(コミット・ロールバック)が期待どおりに動いているか
つまり、「部品同士のつながり」が正しいかどうかです。
単体テストでは「この関数はこう動くべき」と見ていたのに対して、
結合テストでは「この関数とこの関数を組み合わせた“シナリオ”がこう動くべき」と見ます。
単体テストと結合テストの役割分担
単体テストで「ロジック」、結合テストで「つながり」
ざっくり言うと、こういう分担になります。
単体テスト
関数やメソッド単位
外部依存はできるだけ切り離す(mock など)
ロジックの正しさを細かく確認する
結合テスト
複数のモジュール・コンポーネントを組み合わせる
本物に近い DB やフレームワークを使う
シナリオ全体のつながりを確認する
どちらか一方だけでは足りません。
単体テストだけだと、「つなげたときに壊れる」バグを見逃します。
結合テストだけだと、「細かいロジックのバグ」を見つけにくくなります。
だから、現実的には、
重要なロジックには単体テスト
重要なシナリオには結合テスト
という形で、両方をバランスよく持つのが理想です。
結合テストを始めるときの現実的なやり方
まずは「1 つのシナリオ」に絞る
いきなり全部の機能の結合テストを書く必要はありません。
最初は、こういうところから始めるのがおすすめです。
ユーザー登録 → DB 保存 → 再取得
注文作成 → 在庫更新 → 合計金額計算
ログイン → トークン発行 → 認証付き API 呼び出し
つまり、「アプリとして重要な 1 本の流れ」を選びます。
その流れを、
テスト用の DB
テスト用の設定
pytest(+必要なら FastAPI/Flask のテストクライアント)
を使って、コードで再現してみます。
「テスト用の環境」を用意する癖をつける
結合テストでは、「テスト専用の環境」を用意するのがとても大事です。
テスト用の DB(本番とは別の URL)
テスト用の設定ファイルや環境変数
テスト用の API キーやエンドポイント
などを用意して、
「結合テストを何度回しても、本番には一切影響しない」状態を作ります。
その上で、pytest からその環境を使うようにすれば、
安心して「本物に近い動き」をテストできます。
まとめ(結合テストは「つながりと流れ」を守るテスト)
結合テストを初心者目線で整理すると、こうなります。
単体テストが「部品(関数)のテスト」なら、結合テストは「部品をつないだ流れのテスト」。
DB・ORM・Web フレームワークなど、本物に近いものを使って、「保存→取得」「リクエスト→レスポンス」などのシナリオ全体を確認する。
単体テストでロジックの正しさを、結合テストでつながりの正しさを、それぞれカバーすることで、安心して変更できるコードになる。
最初は、アプリの中で特に重要な 1 本のシナリオ(ユーザー登録など)を選んで、そこだけ結合テストを書くところから始めれば十分。
