シングルアサートユニットテストはDRYの原則に違反しませんか?


12

ユニットテストを書くときはいつでも、テストが失敗したときにデバッグを容易にするために、テストごとに1つのアサートをしようと常に試みてきました。しかし、この規則に従うと、各テストで同じコードを常にコピーしているように感じます。テストを増やすことで、読み取りと保守に戻るのが難しくなります。

シングルアサーションテストはDRYに違反していますか?

そして、メソッドごとに1つのテストを行うなど、良いバランスを見つけるために従うべき良いルールはありますか?*

*私はおそらく、これに対するすべてのソリューションに適した1サイズではないことを認識していますが、これにアプローチする推奨方法はありますか?


5
メソッドにコピーしたコードを抽出できます
Ismail Badawi

@IsmailBadawiそれは良いアイデアのように聞こえます。これらのメソッドは、テスト中のクラスオブジェクトのインスタンスを返す必要があると仮定します
Koreyヒントン2013

1
テストする特定の状態で何かを作成していますか?それは備品のように聞こえます。
デイブヒリアー

@DaveHillierはい、今日は新しい言葉を学びました。ありがとう:)
コレイヒントン

テストごとに1つのアサートを解釈する方法に依存します。1つのAssert *呼び出しを意味する場合は、不変式がまだ保持されていることを確認したい場合(それをメソッドに抽出します)、または複数の効果がある場合t単一のアサートでテストする(または実行した場合、失敗した理由は明らかではない)
ラチェットフリーク

回答:


14

適切な単体テストには、失敗したものをすぐに特定するのに役立つ命名規則があります。

public void AddNewCustomer_CustomerExists_ThrowsException()

これが、テストごとに1つのアサーションがあるため、各メソッド(およびその名前)がアサーションしている条件に対応する理由です。

正しく指摘したように、新しいテストにはそれぞれ同様のセットアップコードが含まれます。他のコードと同様に、共通コードを独自のメソッドにリファクタリングして、重複を減らしたり排除したりして、コードをよりドライにできます。一部のテストフレームワークは、そのセットアップコードを1か所配置できるように特別に設計されています

TDDでは、YAGNIはテストではありません。コードを実行するために必要なことだけに基づいてテストを作成するからです。必要ない場合は、テストを作成しません。


単一のメソッドにリファクタリングするのは良いことです。クラスのインスタンスを特定の状態にする必要がある場合、リファクタリングされたメソッドでそのオブジェクトの新しいインスタンスを作成して返すことができます。または、テストフレームワークによって提供されるメソッドを初期テストセットアップに使用することをお勧めします。
コレイヒントン

あなたの最後の点に、私は私がしたい機能のためのテスト書くことができると確信して好きなことは必要ではなく機能性よりも、コードを持っているが
ジョエル・B

5

シングルアサーションテストはDRYに違反していますか?

いいえ、しかし違反を助長します。

とは言っても、優れたオブジェクト指向設計は、ユニットテストの範囲外になる傾向があります-主に正当な理由があります。単体テストを互いに分離して、他のテストを中断しないという自信を持って修正できるように、テストを分離して調査できるようにすることがより重要です。基本的に、テストの正確さと読みやすさは、サイズや保守性よりも重要です。

率直に言って、私はあなたが説明する理由のためにテストルールごとに主張するもののファンではありませんでした:それは読みにくく、間違ったボイラープレートを作りやすく、リファクタリングするとうまく修正するのが難しい多くの定型コードにつながります(これにより、リファクタリングが少なくなります)。

関数が与えられた入力に対して "foo"と "bar"のリストを返すことになっているが、任意の順序で2つのアサートを使用して、両方が結果セットにあることを確認するのは問題ありません。問題が発生するのは、1つのテストで2つの入力または2つの副作用をチェックしているときに、どちらが失敗の原因かわからない場合です。

私はそれを単一責任原則のバリエーションと見なします。テストが失敗する原因は1つだけであり、理想的な世界では、変更は1つのテストのみを中断する必要があります。

しかし、最終的にはトレードオフです。コピーしたすべてのコードを維持するのにより多くの時間を費やす可能性が高いのでしょうか、それとも複数のソースによってテストが破られる可能性のある根本的な原因を探すのにより多くの時間を費やしますか?-some-テストを書く限り、おそらく大した問題ではないでしょう。シングルアサートテストに対する軽disにもかかわらず、私はより多くのテストの側で間違いを犯す傾向があります。あなたのマイレージは異なる場合があります。


1
テストでは、DRY(説明的で意味のあるフレーズ)よりもDAMPであることが重要です。
ヨルグWミットタグ

2

いいえ、これはあなたがやっていることのようです。あなたが彼らがこれが良い習慣であると主張するところに注目すべき参照を見つけない限り。

テストフィクスチャを使用します(ただし、XUnitの用語ではテストセット、セットアップと分解がフィクスチャですが)、つまり、すべてのテストに適用されるセットアップまたは例です。

通常の方法を使用して、コードを構造化します。リファクタリングテストでは、通常のTDD Red-Green-Refactorが適用されず、代わりに「Refactoring in the Red」が適用されます。あれは、

  1. 故意にテストを破り、
  2. リファクタリングを行います
  3. テストを修正する

このようにして、テストがまだ肯定的な結果と否定的な結果を与えることがわかります。

テストにはいくつかの標準形式があります。たとえば、Arrange、Act、Assert、またはGiven When、Then(BDD)など。各ステップに個別の関数を使用することを検討してください。ボイラープレートを減らす関数を呼び出すことができるはずです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.