これらの行テストスタイルの単体テストを改善して、良いTDD設計の慣行に従うことができますか?

.NET TDD/BDDフレームワークのいずれかで、優れたTDD設計プラクティス(ネーミング、ローテストの使用、クラスの設計)に従うために、次のunittestを改善できますか?

また、どのようなフレームワークでも、この(NUnit)の例のように、行ごとに個別の期待を持てるような行テストを行う方が良い方法はありますか?

ここでテストするシステムは、複数の有効な整数の範囲を持つことができる Constraint クラスです。テストでは、 NarrowDown メソッドをテストして、有効範囲を別の制約に基づいて小さくすることができます。

[TestFixture]
internal class ConstraintTests
{
    [Test]
    public void NarrowDown_Works()
    {
        RowTest_NarrowDown(
            new Range[] { new Range(0, 10), new Range(20, 30), new Range(40, 50) },
            new Range[] { new Range(1, 9), new Range(21, 29), new Range(41, 49) },
            new Range[] { new Range(1, 9), new Range(21, 29), new Range(41, 49) });

        RowTest_NarrowDown(
            new Range[] { new Range(0, 10), new Range(20, 30), new Range(40, 50), new Range(60, 70) },
            new Range[] { new Range(1, 9), new Range(21, 29), new Range(41, 49) },
            new Range[] { new Range(1, 9), new Range(21, 29), new Range(41, 49) });

        RowTest_NarrowDown(
            new Range[] { new Range(0, 10), new Range(20, 30), new Range(40, 50) },
            new Range[] { new Range(1, 9), new Range(21, 29), new Range(41, 49), new Range(60, 70) });
    }

    private static void RowTest_NarrowDown(IEnumerable sut, IEnumerable context)
    {
        Constraint constraint = new Constraint(sut);
        Constraint result = constraint.NarrowDown(new Constraint(context));
        Assert.That(result, Is.Null);
    }

    private static void RowTest_NarrowDown(IEnumerable sut, IEnumerable context, IEnumerable expected)
    {
        Constraint constraint = new Constraint(sut);
        Constraint result = constraint.NarrowDown(new Constraint(context));
        Assert.That(result, Is.Not.Null);
        Assert.That(result.Bounds, Is.EquivalentTo(expected));
    }
}
1
入力の各セットは、独立したテストでなければなりません。複数のテストのロジックが同一である場合は、「パラメータ化されたテスト」を使用してください。 NUnitは、パラメータ化されたテストに異なる入力セットを提供する属性またはメソッドを使用します。各セットは、テストランナーによって異なるテストケースとして実行/報告されます。
追加された 著者 Gishu,

2 答え

まず、単体テスト NarrowDown_Works名前を改善するが非常に曖昧で、テスト対象のクラスが何をしているのかを知ることができません。

多くのアサーションがあり、多くのデータがありますが、何が重要かは分かりません。 テストを小さなテストに分割してください。名前を付ける方が簡単になります。可能であれば、テストごとに1つのアサーションを使用してください。

テストデータの作成は非常に複雑です。 NHamcrest のようなマッチャーの使用を検討してください Is.EquivalentTo を使用する代わりに、必要なアサーションデータの量を減らすことができます。

また、 Range の配列を渡すのではなく、 Constraint クラスの初期化を単純化するのにビルダまたはファクトリコンストラクタを使用することもできます。

2
追加された
NHamcrestへのヒント+1
追加された 著者 bitbonk,

データファクトリでデータ駆動型のアプローチを使用する必要があります(NUnitでは、テストケースソースと呼ばれています)。これにより、テストを読みやすく、理解し、変更し、維持するのがずっと簡単になります(もっと一般的には、たくさんのクリーナー)。

[TestFixture]
internal class ConstraintTests
{
    static object[] TwoRanges = 
    {
        new object[]
            {
                new[] { new Range(0, 10), new Range(20, 30), new Range(40, 50) },
                new[] { new Range(1, 9), new Range(21, 29), new Range(41, 49), new Range(60, 70) }
            }
    };

    static object[] ThreeRanges = 
    {
        new object[]
            {
                new[] { new Range(0, 10), new Range(20, 30), new Range(40, 50) },
                new[] { new Range(1, 9), new Range(21, 29), new Range(41, 49) },
                new[] { new Range(1, 9), new Range(21, 29), new Range(41, 49) }
            },
        new object[]
            {
                new[] { new Range(0, 10), new Range(20, 30), new Range(40, 50), new Range(60, 70) },
                new[] { new Range(1, 9), new Range(21, 29), new Range(41, 49) },
                new[] { new Range(1, 9), new Range(21, 29), new Range(41, 49) }
            }
    };

    [Test, TestCaseSource("TwoRanges")]
    public void NarrowDown_WhenCalledWithTwoRanges_GivesTheExpectedResult(IEnumerable sut, IEnumerable context)
    {
        Constraint constraint = new Constraint(sut);
        Constraint result = constraint.NarrowDown(new Constraint(context));
        Assert.That(result, Is.Null);
    }

    [Test, TestCaseSource("ThreeRanges")]
    public void NarrowDown_WhenCalledWithThreeRanges_GivesTheExpectedResult(IEnumerable sut, IEnumerable context, IEnumerable expected)
    {
        Constraint constraint = new Constraint(sut);
        Constraint result = constraint.NarrowDown(new Constraint(context));
        Assert.That(result, Is.Not.Null);
        Assert.That(result.Bounds, Is.EquivalentTo(expected));
    }
}

あなたのテスト方法がどれだけ簡単になったかを見てください。また、これにより、元のテストケースソースからの各データセットが別々のテストで実行されるため、データの1つのセットが失敗するだけですべてが失敗することはありません。覚えておいてください:テストは 1つだけを表明する必要があります。

HTH!

0
追加された