可以改进这些行测试样式单元测试以遵循良好的TDD设计实践吗?

时间:2011-10-27 20:06:53

标签: tdd nunit bdd mspec xunit

是否可以改进以下单元测试,以遵循任何.NET TDD / BDD框架中的良好TDD设计实践(命名,使用行测试,设计类)?

此外,在任何框架中是否有更好的方法来进行行测试,我可以对每一行有个别期望,就像我在这个(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<Range> sut, IEnumerable<Range> context)
    {
        Constraint constraint = new Constraint(sut);
        Constraint result = constraint.NarrowDown(new Constraint(context));
        Assert.That(result, Is.Null);
    }

    private static void RowTest_NarrowDown(IEnumerable<Range> sut, IEnumerable<Range> context, IEnumerable<Range> 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));
    }
}

2 个答案:

答案 0 :(得分:2)

首先,您可以改进单元测试的名称 NarrowDown_Works非常模糊,我无法分辨测试中的课程应该做什么。

你有很多断言和大量数据,我不知道什么是重要的。尝试将测试分解为更小的测试,并且更容易为它们命名。如果可能的话,每次测试使用一个断言

您构建测试数据非常复杂,请考虑使用匹配器(如NHamcrest)来减少所需的断言数据量,而不是使用Is.EquivalentTo

您还可以使用构建器或工厂构造函数来使Constraint类的使初始化更简单更简单,而不是传入Ranges的数组。

答案 1 :(得分:0)

您应该对数据工厂使用数据驱动的方法(在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<Range> sut, IEnumerable<Range> 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<Range> sut, IEnumerable<Range> context, IEnumerable<Range> 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));
    }
}

看看您的测试方法现在变得多么简单了?此外,这将使来自原始测试用例源的每组数据在单独的测试中运行,因此整个事情不会因为一组数据导致失败而失败。请记住:测试应仅断言一个事物。

HTH!