単体テスト:Linqによるアサーションの遅延


18

このような遅延アサーションを追加しても大丈夫ですか

var actualKittens = actualKittens.Select(kitten => {
    Assert.IsСute(kitten);
    return kitten
});

どうして?そのため、たとえば実体化されたコレクションを期待するステートメントでも、一度だけ反復できます。

CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

また、Selectだけでなく、イテレータが定義され、多くのチェックとロジック(たとえば、いくつかのカウントとフィルタリング)を持つメソッドでもあります。

疑いの種は、テストが失敗した場合にそのようなコードを読み取り、デバッグする複雑さです。


1
私はテストのためにこれに依存しませんが、より良い解決策がない場合、実稼働コードでこれを行うことは時々大丈夫です。自分をヘルパー関数にsequence.WithSideEffect(item => Assert.IsCute(item))して、よりきれいにすることができます。
usr

@usrはそのような方法の重要な欠陥を見つけたようです-イテレータからの副作用。
SerG

リストを生成するために1回とそれを比較するために、2回繰り返す必要はありませんexpectedKittensか?メソッド呼び出しの背後に反復を隠しただけです。
IllusiveBrian

@IllusiveBrianこの意味で、この例では、はい。それは追加の場合よりもまだ少ないです.All()
SerG

回答:


37

このような遅延アサーションを追加しても大丈夫ですか?[..]

いいえ、そうではありません。どうして?何らかの理由で2番目のアサートを削除すると、テストはまだ緑に変わり、それでも機能するとは思われますが、コレクションが列挙されないため機能しないためです。2つ以上の独立したアサーションがある場合、それらの1つを無効にしても、彼らは仕事を続けます。

この組み合わせを検討してください。

Assert.IsTrue(actualKittens.All(x => x.IsCute());
CollectionAssert.AreEquivalent(expectedKittens, actualKittens.ToList());

これで、一方のアサートを無効にしたり削除したりしても、もう一方のアサートはそのまま機能します。また、コレクションの具体化を忘れた場合、実行に時間がかかる可能性がありますが、それでも動作します。独立したテストは、より堅牢で信頼性があります。

2番目のnoもあります。他のフレームワークがそれをどのように処理するかはわかりませんが、MS Testプラットフォームを使用している場合、どのテストが失敗したかはわかりません。失敗したテストをダブルクリックすると、失敗したものCollectionAssertとして表示されますが、実際にはネストが失敗し、Assertデバッグが非常に困難になります。以下に例を示します。

    [TestMethod]
    public void TestMethod()
    {
        var numbers = new[] { 1, 2, 3 }.Select(x =>
        {
            Assert.Fail("Wrong number.");
            return x;
        });

        // This will fail and you won't be sure why.
        CollectionAssert.AreEqual(new[] { 1, 2, 3 }, numbers.ToList()); 

    }

これは、バグを見つけるのに役立たないため、最初のテストは実際には役に立たないことを意味します。数値が無効だったために失敗したのか、両方のコレクションが異なるために失敗したのかはわかりません。


どうして?そのため、具体化されたコレクションを期待するステートメントであっても、一度だけ繰り返すことができます

なぜあなたはそれを気にするのだろうか?これらは単体テストです。それらのすべてを最適化する必要はありません。通常、テストでは何百万ものアイテムを必要としないため、パフォーマンスは問題になりません。

このようなテストを維持する必要があるのに、なぜ必要以上に複雑にする必要があるのでしょうか?動作する単純なアサートを記述します。


何らかの理由でアサーションを制御フローに埋め込む必要がある場合、それが実行されたことを確認する1つの方法は、ネストされたアサーションの前にインクリメント/ trueに設定されたカウンター/フラグを保持することです。後で、このカウンタをチェックすることで、予想される制御フローが取られたと断言できます。完全ではありませんが、主に最初の批判に対処します。
アモン

1
さらに、あなたまたは他の誰かが6か月後に遅延アサーションに戻り、それを理解するのに時間を浪費しなければなりません。
DavidTheWin

あなたの例には何か問題があります。呼び出しToListは、列挙型を反復しますか?
ラバーダック

1
@RubberDuckはい、それは失敗しますが、失敗することはありませんが、実際には失敗Assert.FailしたCollectionAssertと言うことはできません。VSはもうAssert.Fail1つに焦点を当てるのではなく、...デバッグできるようになりました。
t3chb0t
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.