他の回答とは反対に、テストがホワイトボックスの場合、テスト対象のシステム(SUT)がリファクタリングされると、テストのいくつかの方法が脆弱になる可能性があることに注意することが重要です。
モックで呼び出されたメソッドの順序を検証するモックフレームワークを使用している場合(呼び出しに副作用がないため順序が関係ない場合)。その後、これらのメソッド呼び出しが異なる順序でコードがきれいになり、リファクタリングすると、テストが失敗します。一般に、モックはテストに脆弱性をもたらす可能性があります。
プライベートまたは保護されたメンバーを公開してSUTの内部状態を確認している場合(Visual Basicで「friend」を使用するか、c#でアクセスレベル「internal」をエスカレートし、「internalsvisibleto」を使用できます。 c#「test-specific-subclass」を使用できます)、クラスの内部状態が突然重要になります-クラスをブラックボックスとしてリファクタリングすることはできますが、ホワイトボックステストは失敗します。SUTの状態が変化したときに単一のフィールドが異なることを意味するために再利用されたとしましょう(良い習慣ではありません!)。
テスト固有のサブクラスを使用して、保護されたメソッドをテストすることもできます。これは、生産コードの観点からのリファクタリングがテストコードの観点からの重大な変更であることを意味する場合があります。保護されたメソッドにいくつかの行を出し入れすると、実動の副作用はないかもしれませんが、テストは中断します。
「テストフック」またはその他のテスト固有または条件付きコンパイルコードを使用する場合、内部ロジックへの脆弱な依存性のためにテストが中断しないことを保証するのは困難です。
したがって、テストがSUTの親密な内部詳細に結び付くのを防ぐには、次のことが役立ちます。
- 可能であれば、モックではなくスタブを使用してください。詳細については、Fabio Perieraのトートロジー検査に関するブログと、私のトートロジー検査に関するブログをご覧ください。
- モックを使用する場合は、重要でない限り、呼び出されたメソッドの順序を確認しないでください。
- SUTの内部状態を検証しないようにしてください-可能であれば、外部APIを使用してください。
- 本番コードでのテスト固有のロジックを避けるようにしてください
- テスト固有のサブクラスを使用しないようにしてください。
上記のすべてのポイントは、テストで使用されるホワイトボックスカップリングの例です。したがって、破損テストのリファクタリングを完全に回避するには、SUTのブラックボックステストを使用します。
免責事項:ここでリファクタリングを議論する目的で、目に見える外部効果なしに内部実装の変更を含めるために、私はもう少し広く言葉を使用しています。一部の純粋主義者は、マーティン・ファウラーとケント・ベックの本「リファクタリング-アトミックリファクタリング操作について説明している」に異議を唱え、排他的に言及する場合があります。
実際には、そこで説明されているアトミック操作よりもわずかに大きなノンブレークステップを実行する傾向があります。特に、外部から本番コードが同じように動作する変更は、テストに合格しない場合があります。しかし、リファクタリングとして「同一の動作をする別のアルゴリズムの代替アルゴリズム」を含めることは公平だと思います。ファウラーも同意すると思います。Martin Fowler自身は、リファクタリングはテストを破るかもしれないと言っています:
モックテストを作成するときは、SUTの発信呼び出しをテストして、サプライヤーと適切に通信することを確認します。古典的なテストでは、最終状態のみが考慮され、その状態がどのように導出されたかは考慮されません。そのため、Mockistテストはメソッドの実装により密接に結合されます。共同編集者への呼び出しの性質を変更すると、通常、模擬テストが中断します。
[...]
実装の変更は、従来のテストよりもテストを壊す可能性がはるかに高いため、実装への結合もリファクタリングの妨げになります。
ファウラー- モックはスタブではありません