testify suite はサブテスト間で mock 状態を共有する — エラー系は分離する
Go
テスト
testify
stretchr/testify の suite.Suite で、1 つの Test メソッド内に複数の suite.Run(...) サブテストを並べ、mock セットを SetupTest で 1 度だけ生成して使い回す構成では、サブテスト間で mock の登録状態(expectation)が共有される点が落とし穴になる。SetupTest はメソッド単位で呼ばれ、同一メソッド内の各 suite.Run の前後では走らないため、先行サブテストで登録した expectation が後続サブテストに残る。
何が壊れるか: 回数指定のない成功 mock(.Once() を付けず常時マッチする On(...).Return(成功))を正常系サブテストで登録すると、同じメソッド内の後続の異常系サブテストでもそのマッチが効いてしまい、本来エラーを返すはずの分岐が成功で素通りする。結果「エラーになるはず」のテストが偽陰性(err が nil)になり、未到達分岐を埋めたつもりが実は通っていない、という事故が起きる。トランザクション内の成功 mock やヘルパー(成功 Tx をセットする系)は特に常時マッチになりやすく汚染源になる。
対処の判断基準:
- 同一メソッド内で正常系と、その成功 mock と衝突する異常系を併置しない。衝突するエラー系は 1 ケース 1 トップレベル Test メソッドに分離する(メソッドが変われば
SetupTestで mock が作り直され、状態が混ざらない)。 - 1 メソッド内に複数ケースを置くなら、各 expectation に
.Once()(または回数指定)を付け、ケースをまたいで使い回されないようにする。 TearDownTestでAssertExpectationsを呼ぶ運用なら、各ケースで「実際に呼ばれる mock だけを過不足なく登録」する規律と合わせると、余剰 expectation の残留にも気づきやすい。
気づき方: 異常系サブテストで err が nil になる/アサーションが意図せず通る場合、まず同一メソッド内の先行サブテストが常時マッチの成功 mock を残していないかを疑う。
適用条件: xUnit 系の suite/fixture で setup が「ケース単位」ではなく「メソッド単位」で走り、mock 状態を共有する構成全般(testify suite に限らず、setup 粒度とサブテスト粒度がずれるテストフレームワークで再現しうる)。