backend
B
信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
ハーネスエンジニアリング: 時刻依存バグを潰すClock抽象化
現在時刻を直接呼ばず、注入可能なClockで制御する。
一言結論
現在時刻を直接呼ばず、注入可能なClockで制御する。
背景
現在時刻を直接呼ばず、注入可能なClockで制御する。 ハーネス設計はテストコードの書き方ではなく、失敗を再現可能にするシステム設計です。時刻制御による決定性向上を軸に、CI運用で効く具体策を整理します。
設計原則(網羅)
- 決定性: 時刻・乱数・外部I/Oを制御可能にする。
- 隔離性: テスト間で状態を共有しない。
- 観測性: 失敗時に原因追跡できるログ粒度を持つ。
- 再現性: seed/入力/依存バージョンを固定・記録する。
- 経済性: CI時間と調査工数の総和を最小化する。
具体例: CIでのみ失敗するケース
- 現象: ローカルでは成功、CI並列実行時だけ失敗。
- 原因候補: 時刻依存、順序依存、外部サービスの揺らぎ。
- 対策:
- clock/seed/networkを注入可能なインターフェースへ。
- テストID単位で専用DBスキーマを割り当て。
- 失敗時に同seed再実行 + 依存スナップショット保存。
時刻制御による決定性向上を実現する実装パターン
Arrange: 依存差し替え(clock, rng, io)
Act: 1シナリオ1目的で実行
Assert: 出力 + 副作用 + 監視ログを同時検証
Recover: seed再実行で再現性を確認
メトリクス駆動で改善する
| 指標 | 定義 | 目標 |
|---|---|---|
| Flake率 | 再試行で成功する失敗比率 | <2% |
| MTTD | 失敗から原因仮説まで | 30分以内 |
| MTTR(test) | テスト修正完了まで | 1営業日以内 |
| CI先頭失敗検知 | 失敗を最初に検知するまで | 10分以内 |
深掘り: チーム運用での落とし穴
- Fixture肥大化: 便利関数が巨大化し、意図不明なテストが増える。
- Golden崩壊: 期待値更新を機械的に承認し、退行を見逃す。
- 過剰モック: 実環境差分を隠して本番不具合を誘発。
- 計測欠如: Flake率未計測で“たまに落ちる”を放置。
ニッチ実務ノート
- ネットワーク模擬では平均遅延よりもjitter/burst/drop率の設定が効く。
- コンテナ並列でのポート競合は、動的ポート配布より名前空間分離が安定。
- 時刻制御はUTC固定に加え、DST境界ケースを専用テスト化すると事故が減る。
- Golden比較は完全一致と構造一致を使い分ける(例: JSONは順序非依存)。
現場導入チェックリスト
- 失敗時にseedと依存バージョンを自動保存している
- 外部I/Oを含むテストを層分離している
- 並列実行時の隔離戦略(DB/FS/Queue)を持つ
- Flake検知と隔離ルールがある
- 毎週、失敗上位ケースをハーネス改善へ還元している
まとめ
ハーネスエンジニアリング: 時刻依存バグを潰すClock抽象化 はテスト追加よりも「失敗を工学的に扱う仕組み化」が本質です。決定性・隔離性・観測性を数値で運用すると、CIは品質ゲートとして機能し続けます。