单元测试c#属性
我和一个有很多属性的类一起工作。比如,单元测试c#属性,c#,.net,tdd,xunit,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 = expec
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);
}
在这里,我讨厌我如何硬编码expected=3。对于accessor和mutator,测试此属性的好方法是什么?由于此属性除了作为整数的getter/setter之外没有其他行为,因此您实际上只是测试编译器是否工作。这基本上不会给测试增加任何价值。考虑完全移除它。那会使你摆脱这种奇怪的处境
如果您确实有一些您试图捕获的行为(例如,允许的边界条件),您只需要测试这些行为,实际上不需要其他。通常,这些边界条件的常数作为对象的一部分可用。考虑使用这些常量,+/一些适当的增量。 < P>我坚信单元测试是“白盒”测试,这意味着你可以使用已知的角落情况来选择你的测试输入。在这种情况下,如果使用auto属性,那么如果您信任您的编译器,那么测试是不必要的。如果您不能信任编译器以您期望的方式实现自动属性,那么您也不能信任它以您编写的方式执行测试 也就是说,如果您有一个更复杂的setter,您将根据可能的故障情况选择输入。几个典型案例:
- 验证>=0的属性的负数
- 其他验证失败
- 极端的边界情况,如Int.MaxValue,有时会触发setter中的溢出和意外行为
- 应该通过验证的任意值(这里没有关于如何选择值的实际指导,只要您知道它在您的“好”情况下。)
- 这应该有助于
[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);
}
[事实]
public void CanGetAndSetPartQuantity()
{
布尔失败=错误;
int预期为0;
而(!fail&&expected
非常适合这种单元测试。改为这样写:
[Fact]
public void CanGetAndSetPartQuantity()
{
const int expected = new Random().Next();
var target = new Bib() {PartQty = expected};
Assert.Equal(expected, target.PartQty);
}
这确保了无论输入是什么,输出都能正确地表示输入。我刚才听了一篇关于良好单元测试实践的演讲(很抱歉,这个家伙的名字逃过了我脆弱的记忆)。他提倡使用精心挑选的名称在常量中存储这样的值 在你的情况下,我会用这样的名字
const int SomeRandomValidPartQuantity=3;
通过这种方式,您表示要准确使用此值,在这种情况下,您只是在寻找任何有效数量 测试应该来自某种用例。有趣的是,首先你介绍了你的类,然后谈到编写一个测试,这是向后TDD的 用例通知测试,测试通知代码。我非常怀疑您的用例是“我的API的用户可以将名为
PartQty
的属性设置为任何整数,并始终返回他们设置的整数”。如果这是真正的用例,您应该编写一个单元测试来检查int.MaxValue
和int.MinValue
。然而,这些很少是现实世界的价值观
一个真实的用例可能会是这样的:“我的API的用户向Bib
注入IFlugleBinder
,将PartQty
设置为4,然后调用Execute
方法。这会在IFlugleBinder
实例上调用Bind
方法4次。”如果这是用例,你的测试看起来会很不一样
老实说,它看起来像是某种DTO。根据我的经验,大多数DTO只是一些更高级别用例的产物。如果DTO是作为API提供的函数调用的结果返回的,那么您实际上应该返回一个接口,DTO类本身应该是私有的,在这种情况下,不需要显式地测试它(只需测试从方法调用获得的实际结果的属性)。同样,如果它是一个从未公开的内部DTO,那么就不要公开它。如果您的用户必须提供一些值包,那么您的API应该接受一个接口。让用户定义自己实现接口的类,或提供一个不可变的类,如下所示:
public class Bib : IBib
{
public Bib(int partQty)
{
PartQty = partQty;
}
public int PartQty { get; private set; }
}
[Theory]
[AutoData]
public void CanGetAndSetPartQuantity(int expected)
{
var target = new Bib() {PartQty = expected};
Assert.Equal(expected, target.PartQty);
}
然后你可以编写一个测试来检查你的构造函数是否工作,如果你想学究的话,但这并不是那么重要。虽然我也认为这属于“测试到无聊”类别,但如果你确实觉得这是值得测试的,批准测试提供了一种非常简单的测试方法。附件是一个检查属性的简单测试
[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:
努尼特:
Xunit:您还可以像这样使用autofixture autodata属性:
public class Bib : IBib
{
public Bib(int partQty)
{
PartQty = partQty;
}
public int PartQty { get; private set; }
}
[Theory]
[AutoData]
public void CanGetAndSetPartQuantity(int expected)
{
var target = new Bib() {PartQty = expected};
Assert.Equal(expected, target.PartQty);
}
您可能使用了一个“神奇数字”,但至少您在测试中只声明了一次-因此我很难看出问题所在。您是否希望.NET Framework停止工作?我不建议为自动属性编写测试。与这里的公众观点相反,在生成库时,这种测试是非常有效的。与其说是成功,不如说是编译时没有错误。单元测试执行这两个功能。即使没有单元测试,它也会编译无误,前提是该属性曾经被使用过。如果没有使用它,那么它就不应该存在。在生成库时,这种测试是非常有效的,因为您可能会在稍后的某个时间点决定为属性使用更复杂的getter或setter逻辑,并且该测试将确保在该时间到来时不会破坏任何东西。我假设这是一个