11

我正在使用一个有很多属性的类。例如;

public class Bib
{        
    public int PartQty { get; set; }
}

现在进行单元测试;我做了类似的xUnit测试

    [Fact]
    public void CanGetAndSetPartQuantity()
    {
        const int expected = 3;

        var target = new Bib() {PartQty = expected};

        Assert.Equal(expected, target.PartQty);
    }

在这里,我讨厌我如何硬编码预期 = 3。为访问器和突变器测试此属性的好方法是什么?

4

8 回答 8

16

由于此属性除了作为整数的 getter/setter 之外没有其他行为,因此您实际上只是在测试编译器是否工作。这基本上不会为您的测试增加任何价值。考虑完全删除它。这会让你摆脱这种奇怪的情况。:)

如果你确实有一些你试图捕捉的行为(例如,允许的边界条件),你只需要测试那些,实际上没有别的。通常,您将拥有可作为对象一部分的边界条件的常量。考虑使用这些常量,+/- 一些适当的增量。

于 2011-05-03T23:18:05.330 回答
9

受约束的非确定性非常适合这种单元测试。改为这样写:

[Fact]
public void CanGetAndSetPartQuantity()
{
    const int expected = new Random().Next();

    var target = new Bib() {PartQty = expected};

    Assert.Equal(expected, target.PartQty);
}

这确保了输出正确地表示输入,无论输入是什么。

于 2011-05-04T07:33:52.610 回答
6

我坚信单元测试是“白盒”测试,这意味着您可以使用已知的极端案例来选择您的测试输入。在这种特殊情况下,使用自动属性,如果您信任您的编译器,则无需进行测试。如果您不能信任编译器以您期望的方式实现自动属性,那么您也不能信任它执行您编写的测试。

也就是说,如果你有一个更复杂的设置器,你会根据可能的失败案例来选择你的输入。几个典型案例:

  • 验证 >= 0 的属性的负数
  • 其他验证失败
  • 极端边界情况,例如 Int.MaxValue,有时会触发 setter 中的溢出和意外行为
  • 应该通过验证的任意值(对于如何在此处选择值没有真正的指导,只要您知道它在您的“好”情况下。)
于 2011-05-03T23:18:40.813 回答
2

这应该有帮助...

[Fact]     
public void CanGetAndSetPartQuantity()     
{
    bool fail = false;
    int expected = 0;

    while (!fail && expected < int.MaxValue)
    {
        var target = new Bib() {PartQty = expected};          
        fail = expected != target.PartQty;
        expected++;
    }

    Assert.IsTrue(!fail);
} 
于 2011-05-03T23:38:06.707 回答
2

不久前,我观看了一个关于良好单元测试实践的演示文稿(抱歉,这个人的名字逃过了我脆弱的记忆)。他提倡使用经过精心挑选的名称将类似的值存储在常量中。

在您的情况下,我会使用类似的名称

const int SomeRandomValidPartQuantity=3;

这样,您就表明了使用该值的意图,在这种情况下,您就在任何有效数量之后。

于 2011-05-04T13:33:41.650 回答
2

测试应该来自某种用例。有趣的是,您首先介绍了您的课程,然后谈到了编写测试,这倒退到了 TDD。

用例通知测试,测试通知代码。我非常怀疑您的用例是“我的 API 的用户可以设置一个调用PartQty任何整数的属性并始终取回他们设置的整数”。如果那是真正的用例,您将编写一个单元测试来检查int.MaxValueint.MinValue. 然而,这些很少是现实世界的价值。

一个真实的用例可能看起来像:“我的 API 的用户通知Bib注入 an IFlugleBinder,将 设置PartQty为 4,然后调用该Execute方法。这会调用实例Bind上的方法IFlugleBinder4 次。” 如果那是用例,您的测试看起来会非常不同。

老实说,它看起来Bib只是某种 DTO。以我的经验,大多数 DTO 只是一些更高级别用例的产物。如果 DTO 作为 API 提供的函数调用的某个结果返回,那么您确实应该返回一个接口,并且 DTO 类本身应该是私有的,在这种情况下,不需要显式测试它(只需测试属性您从方法调用中获得的实际结果)。同样,如果它是从未公开的内部 DTO,则不要将其公开。如果您的用户必须提供一些值,那么您的 API 应该接受一个接口。让用户定义自己的实现接口的类,或者提供一个不可变的类,如下所示:

public class Bib : IBib
{
    public Bib(int partQty)
    {
        PartQty = partQty;
    }
    public int PartQty { get; private set; }
}

然后你可以编写一个测试来检查你的构造函数是否工作,如果你想学究气,但这并不重要。

于 2011-05-04T13:44:59.843 回答
2

虽然我也相信这属于“测试到无聊”类别,但如果您确实觉得这值得测试,则批准测试提供了一种非常简单的测试方法。附件是一个检查属性的简单测试。

[TestMethod]
[UseReporter(typeof(DiffReporter))]
public void TestMethod1()
{
    var fred = new Person{
            Age = 35,
        FirstName = "fred",
        LastName = "Flintstone",
        Hair = Color.Black
           };
    Approvals.Verify(fred.WritePropertiesToString());
}

这将生成一个文件,内容如下:

Person
{
    Age: 35
    FirstName: fred
    LastName: Flintstone
    Hair: Color [Black]
}

只需将该文件重命名为 .approved 即可。

注意扩展方法的使用:.WritePropertiesToString()

这里有一个关于批准测试基础的视频

女士测试: http ://www.youtube.com/watch?v= bg8GOmlwqYY

Nunit:http ://www.youtube.com/watch?v=aO_fyZBxaFk

Xunit:http ://www.youtube.com/watch?v=8wPx0O4gFzc

于 2012-04-24T16:21:24.547 回答
0

您也可以像这样使用 autofixture 自动数据属性:

        [Theory]
        [AutoData]
        public void CanGetAndSetPartQuantity(int expected)
        {
            var target = new Bib() {PartQty = expected};

            Assert.Equal(expected, target.PartQty);
        }
于 2018-08-28T05:24:37.953 回答