ユニットと統合テスト
1)テストタイプを区別する理由
テストの適切な粒状化は、開発を予測可能にします:ユニットキャッチ論理欠陥迅速かつ安価に;統合はモジュール、実質の輸送および"接着剤の束を点検します。"一緒に、彼らは回帰を減らし、リリースを加速します。
2)定義と境界
ユニットテスト
小単位の動作(関数、クラス、ユースケース)を分離してテストします。
外部依存関係は置き換えられます(モック/スタブ/偽)。
速い(ms-tens of ms)、決定論的。
統合テスト
データベース、ブローカー(Kafka/RabbitMQ)、 HTTP/gRPC、ファイルシステム、キャッシュなど、いくつかの実際のコンポーネントの相互作用をチェックします。
最小限のモック、実際のプロトコル。
より遅く(数百ミリ秒)、より高価なサポート。
3)テストのピラミッド(ない氷の角)
基礎:単位(数の70-80%)-安く、速い。
中間レイヤー:統合/コンポーネント(15-25%)-重要なパスと契約。
トップ:E2E/UX/Exploratory (5-10%)-最小で十分です。
側面:品質アンプとして静解析/リント/タイプチェックと突然変異テスト。
4)ユニットに何を与えるか、何を統合するか
5)データと修正
ユニット(Unit)
インラインフィクション/ビルダー(工場メソッド)。
境界値のテーブル駆動テスト。
不変量に対するプロパティベースのアプローチ(例:「デビットの合計=クレジットの合計」)。
インテグレーション
Hermetic環境:Testcontainers/Docker 「postgres+redis+kafka+wiremock」を上げる。
データベース/キャッシュの初期シードと後のクリーンアップ(トランザクション/ロールバック、切り捨て)。
時計/タイマーは偽(制御)、そうでなければフラックです。
6)用具およびパターン
モック/スタブ/偽物/スパイ:- スタブは固定の答えです(安い)。
- モック-インタラクション/コール数をチェックします。
- Fakeは簡略化された実装です(例えば、In-Memory Repo)。
- 契約テスト(CDC): Pact/Swaggerベース-顧客の期待を修正し、プロバイダを確認します。
- WireMock/MockServer-サードパーティサービス用のHTTPスタブ。
- Testcontainersは「動物園」なしでローカルとCIでライブDB/ブローカーです。
7)例
7.1単位:支払Idempotence(擬似コード)
python def test_idempotent_create_payment_returns_same_id():
repo = InMemoryPayments()
service = Payments(repo)
first = service. create(amount=100, key="abc")
second = service. create(amount=100, key="abc")
assert first. id == second. id assert repo. count() == 1
7.2統合:Webhook署名(HMAC)+繰り返し
bash docker-compose: app + redis + wiremock (PSP)
docker compose -f docker-compose. test. yml up -d pytest -m "integration and webhook" -q
テスト:
- WireMockは'X-Timestamp'と署名を持つイベントを提供します。
- アプリケーションはHMACをチェックし、'event_id'で重複除外し、5秒後に繰り返してもダブルは作成されません。
- 「200」をチェックします。エントリは1つだけです。
7.3 CDC:プロバイダへの顧客契約
クライアントはPact ('POST/v1/payout'→'201')を生成します。
CIのプロバイダは、そのスタンドで契約の検証を実行します。
8)速度、平行、フレーク
単位はテストごとの<100 msを動かさなければなりません;パケット-秒。
統合-コンテナ/ポートによる並列;スタートアップマイグレーションを使用します。
- 制御された時間(偽の時計)、
- 期待は「明示的な出来事によって」、'睡眠'ではなく、
- 安定したしきい値(決定的にジッタテストを伴うレトライ)。
9)品質指標
カバレッジ(ライン/ブランチ):トレンドを観察するのに便利ですが、ターゲットではありません。
Mutation Testing (PIT/Mutmut):テストが「kill」 falseの変化-暗殺者の実力-を示す。
テスト期間とフレーク率:成長時のアラート。
欠陥の封じ込め:生産前に傍受されたバグの割合。
10) CI/CDに埋め込むこと
ジョブ:ユニット→インテグレーション→e2e(サービス別ファンアウト)。
依存関係キャッシュ、データベース/言語/バージョンによる並列行列。
レポート:JUnit/Allure+コンテナログアーティファクト(ドロップ用)。
ゲート:「グリーンユニット+クリティカル統合」-マージ条件;e2e-夜に。
yaml strategy:
matrix:
db: [postgres14, postgres16]
steps:
- run: docker run -d --name db -e POSTGRES_PASSWORD=pw postgres:${{ matrix. db }}
- run: pytest -m "unit" -q
- run: pytest -m "integration" -q
11)マイクロサービスとイベント
サービス契約:OpenAPI/Protobufはバージョン管理されています。互換性テスト(後方)。
イベントドリブン:- 単位:ドメインイベントマッピングと不変量。
- 統合:実際のブローカー(Kafka)での出版/サブスクリプション、outbox/inboxセマンティクス、正確に一度の模倣(少なくとも-idempotent)。
- アウトオブオーダーテスト。
12)統合におけるデータと分離
各テスト→一意のスキーマ/データベース(Testcontainers JDBC URL'?TC_TMPFS =/var/lib/postgresql/data: rw')。
トランザクション修正(begin→run→rollback)により、クリーニングが高速化されます。
Redis/cacheの場合、キーのプレフィックスは'test:${RUN_ID}:'と'FLUSHDB'です。
13) iGaming/Financeの詳細
金額と限度額:不変量(残高≥ 0、総制限額)に対する不変量ベースのテスト。
規制:ロギングチェック(監査ログが書かれています)、変更できないイベント。
支払い/PSP: HMAC/mTLS統合テスト、'Retry-After'、 idempotency、 dedup 'jti'。
責任あるプレー:しきい値/クールダウンルールテスト;偽の時計に「vchera→segodnya」。
14) Antipatterns
DB/HTTPを上げる「ユニット」はすでに統合されています(レイヤーを混乱させ、CIを遅くします)。
空のステートメントによる高いカバレッジ(「カバーされているがチェックされていない」)。
契約が必要なサードパーティサービスのモキロジック(更新時に壊れます)。
イベント/条件期待の代わりに'sleep (5)'でテストします。
並列テスト→レースとフレークの一般的なテストデータベース。
15) Prod Readinessチェックリスト
- ピラミッドは実行時間によってUnit/Integration/E2Eとターゲットの共有の%として定義されます。
- 単位は絶縁され、高速で、境界値と不変量をカバーします。
- インテグレーションは、共通の状態を持たない密閉環境(Testcontainers/Compose)を使用します。
- 契約テスト(OpenAPI/Pact)がCIで検証されます。
- テストデータ-管理:シード/ロールバック/プレフィックス、偽クロック。
- 並列実行、JUnit/Allureレポート、コンテナログアーティファクト。
- メトリクス:期間、フレーク率、突然変異スコア;劣化を警告します。
- 支払/webhookシナリオ:HMAC/mTLS、 retrai、 idempotency、 deadup。
- 戦略文書とサンプルテストテンプレート。
16) TL;DR(ドクター)
単位-最高の論理、最低の環境;統合-最小モック、最大リアリズム。ピラミッドを保持する:ファストユニットは欠陥の80%をキャッチし、統合はバンドルと契約を確認します。密閉容器、契約テスト、偽の時計と並列性を使用してください。カバレッジだけでなく、変異スコアとフレーク率も測定します。特に、payment/webhookのパスを確認します。署名、リトレイ、idempotencyです。