单元测试c#属性

时间:2011-05-03 23:11:36

标签: c# .net tdd xunit

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

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.有什么方法可以测试访问者和mutator的这个属性?

8 个答案:

答案 0 :(得分:14)

由于此属性除了作为整数的getter / setter之外没有任何行为,因此您基本上只是测试编译器的工作原理。这基本上没有为您的测试增加任何价值。考虑完全删除它。这可以减轻你这种奇怪的情况。 :)

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

答案 1 :(得分:8)

Constrained Non-determinism非常适合这种单元测试。这样写它:

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

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

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

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

答案 2 :(得分:6)

我坚信单元测试是'白盒'测试,这意味着你可以使用已知的角落情况来选择你的测试输入。在这种具有自动属性的特殊情况下,如果您信任编译器,则不需要进行测试。如果您不能相信编译器以您期望的方式实现自动属性,那么您也不能相信它可以像您所写的那样执行测试。

也就是说,如果你有一个更复杂的setter,你可以根据可能的失败案例选择你的输入。一些典型案例:

  • 验证> = 0
  • 的属性的负数
  • 其他验证失败
  • 极端边界情况,如Int.MaxValue,有时会触发setter中的溢出和意外行为
  • 应该通过验证的任意值(没有关于如何在此处选择值的实际指导,只要您知道它在'好'的情况下。)

答案 3 :(得分: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);
} 

答案 4 :(得分:2)

前一段时间我接受了关于良好的单元测试实践的演示文稿(对不起,但这个人的名字逃脱了我脆弱的记忆)。他主张使用精心挑选的名称来存储常量中的值。

在你的情况下,我会使用像

这样的名字
const int SomeRandomValidPartQuantity=3;

通过这个,你发出准确使用这个值的意图,在这种情况下,你只是在任何有效数量之后。

答案 5 :(得分:2)

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

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

真实世界的用例可能如下:“我的API新闻用户Bib注入IFlugleBinder,将PartQty设置为4,然后调用{{ 1}}方法。这会在Execute实例上调用Bind方法4次。“如果那是用例,那么您的测试看起来会非常不同。

老实说看起来IFlugleBinder只是某种形式的DTO。根据我的经验,大多数DTO只是一些更高级用例的工件。如果DTO是由API提供的函数调用返回的,那么你应该真正返回一个接口,并且DTO类本身应该是私有的,在这种情况下,没有必要显式地测试它(只需测试属性)您从方法调用获得的实际结果)。同样,如果它是一个从未暴露过的内部DTO,那么就不要公开它。如果您的用户必须提供一些值,那么您的API应该接受一个接口。让用户定义自己的实现接口的类,或者提供一个不可变的类,如下所示:

Bib

然后你可以编写一个测试来检查你的构造函数是否有用,如果你想要迂腐,但它并不重要。

答案 6 :(得分: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()

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

MsTest:http://www.youtube.com/watch?v=bg8GOmlwqYY

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

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

答案 7 :(得分:0)

您还可以使用autofixture autodata属性,如下所示:

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

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