web-dev-qa-db-ja.com

単体テストで複数のアサーションが悪いですか?連鎖しても?

このユニットテストでこれほど多くのことをチェックすることに何か問題がありますか?:

ActualModel = ActualResult.AssertViewRendered()        // check 1
                          .ForView("Index")            // check 2
                          .WithViewData<List<Page>>(); // check 3

CollectionAssert.AreEqual(Expected, ActualModel);      // check 4

このテストの主な目的は、正しいビューが返され(チェック2)、正しいデータが含まれていること(チェック4)を確認することです。

これを複数のテストに分割することで何かを得ることができますか?私は物事を正しく行うことがすべてですが、実用的な価値がない場合は、物事を分割するつもりはありません。

私はユニットテストにかなり慣れていないので、優しくしてください。

41
Michael Haren

他の人が指摘しているように、情報の損失を避けるために、各テストで1つのアサーションを使用するのが最善です。最初のアサーションが失敗した場合、後のアサーションも失敗するかどうかはわかりません。あなたはより少ない情報で問題を修正しなければなりません-それは(おそらく)より難しいかもしれません。

非常に良い参考資料は、Roy Osheroveの Art of Unit Testing -ユニットテストを正しく開始したい場合は、ここから開始するよりもはるかに悪いことをする可能性があります。

30
Bevan

将来の読者のために、この質問とその重複 単体テストで複数のアサーションを持つのは悪い習慣ですか? 反対の多数意見があるので、両方を読んで自分で決めてください。

私の経験では、テストの最も有用な量はアサーションではなく、シナリオです。つまり、特定の初期条件とメソッド呼び出しのセットに対して1つの単体テストがあり、アサーションをアサートするために必要な数のアサーションが必要です。予想される最終条件。アサーションごとに1つのユニットテストを行うと、重複を回避するための重複したセットアップまたは曲がりくねった回避策につながります(最近ますます見られるひどく深くネストされたrspecコンテキストなど)。また、テストが増加し、スイートの速度が大幅に低下します。

12

各アサーションに一意の識別可能な失敗メッセージがある限り、どのテストが失敗したかを判断するのは難しくないため、アサーションルーレットの問題を回避できます。常識を使用してください。

8
John K

私はこの質問に対する別の議論を見つけました(少なくとも私にとっては):

同じことをテストしている場合は、複数のアサーションを使用しても問題ありません。

たとえば、次のことを実行しても問題ありません。

Assert.IsNotNull(value);
Assert.AreEqual(0, value.Count);

どうして? -これらの2つのアサートは、テストの意図を隠していないためです。 最初のアサーションが失敗した場合、2番目のアサーションも失敗することを意味します。実際、最初のアサーションを削除すると、valueがヌル。そうでない場合は、これら2つのアサートを一緒にしないでください。

だから、これは間違っています:

Assert.IsNotNull(value1);
Assert.IsNotNull(value2);

上で述べたように、最初のアサーションが失敗した場合、2番目のアサーションについて明確な兆候はありません-2番目のアサーションがどうなるかを知りたいと思います(最初のアサーションが失敗した場合でも) 。したがって、このため、これら2つのアサーションは2つの異なる単体テストに属します。

結論:1つ以上のアサーションを配置すること適切に行われた場合は、好みの問題になります-テスト結果にアサーション例外を表示するかどうか。特定の場合に、他のいくつかの例外も表示したいですか。

7
Tengiz

アサーションルーレット を回避するために、各テストで1つのアサーションのみを使用することをお勧めします。

同じ前提に基づいて複数の条件をテストするために同じシナリオを設定する必要がある場合は、設定コードを共有ヘルパーメソッドに抽出してから、このヘルパーメソッドを呼び出すいくつかのテストを作成することをお勧めします。

これにより、各テストケースでテストされるのは1つだけになります。

いつものように、このルールには例外がありますが、ユニットテストは初めてなので、ユニットごとに1つのアサーションを使用することをお勧めします。 testは、逸脱しても問題がないことを学習するまでルールを設定します。

2
Mark Seemann

これは古い質問であることは知っていますが、少し追加したいと思いました。

通常、各テストケースでアサーションをできるだけ少なくします。多くの場合、テストは、多くの異なるアサーションを持つことを節約するために作成できます。

名前のコンポーネントからあいさつ文(Smith氏など)を作成するメソッドの単体テストがあるとします。さまざまなシナリオでこれを確認したいので、それぞれに個別のテストを行う必要はありません。

次のコードを考えると、多くの異なるアサーションがあります。それらが失敗した場合、アサーションが停止するまで一度に1つずつ修正できます。

Assert.AreEqual("Mr Smith", GetSalutation("Mr", "J", "Smith"));
Assert.AreEqual("Mr Smith", GetSalutation("Mr", "John", "Smith"));
Assert.AreEqual("Sir/Madam", GetSalutation("", "John", "Smith"));
Assert.AreEqual("Sir/Madam", GetSalutation("", "J", "Smith"));

これに代わる方法は、問題の数を保持し、最後にこれを表明することです。

int errorCount = 0;
string result;

result = GetSalutation("Mr", "J", "Smith");
if (result == "Mr Smith")
    errorCount++;

result = GetSalutation("Mr", "John", "Smith");
if (result == "Mr Smith")
    errorCount++;

Assert.AreEqual(0, errorCount);

実際の状況では、出力ウィンドウに失敗した個々のテストの詳細を書き込むために、おそらくいくつかのトレースコマンドを追加します

0
timbo