【发布时间】:2012-01-10 00:34:08
【问题描述】:
这是我第一次尝试做单元测试,请耐心等待。
I'm still trying to unit test a library that converts lists of POCOs to ADO.Recordsets.
现在,我正在尝试编写一个创建 List<Poco> 的测试,将其转换为 Recordset(使用我想要测试的方法),然后检查它们是否包含相同的信息(例如,如果 @987654325 @,等等...)。
这是 POCO:
public class TestPoco
{
public string StringValue { get; set; }
public int Int32Value { get; set; }
public bool BoolValue { get; set; }
}
...这是迄今为止的测试(我正在使用 xUnit.net):
[Fact]
public void TheTest()
{
var input = new List<TestPoco>();
input.Add(new TestPoco { BoolValue = true, Int32Value = 1, StringValue = "foo" });
var actual = input.ToRecordset();
Assert.Equal(actual.BoolValue, true);
Assert.Equal(actual.Int32Value, 1);
Assert.Equal(actual.StringValue, "foo");
}
我不喜欢最后的三个断言,每个 POCO 的属性一个。
我已经读过很多次了,一个测试中的多个断言是邪恶的(我理解其中的原因,我同意)。
问题是,我怎样才能摆脱它们?
我面前有 Roy Osherove 的优秀书籍 "The Art of Unit Testing",他有一个例子正好涵盖了这一点(对于那些拥有这本书的人:第 7.2.6 章,第 202/203 页) em>:
在他的示例中,被测方法返回一个带有多个属性的AnalyzedOutput 对象,他想要断言所有属性以检查每个属性是否包含预期值。
这种情况下的解决方法:
创建另一个AnalyzedOutput 实例,用预期值填充它,并断言它是否等于被测方法返回的值(并覆盖Equals() 以便能够做到这一点)。
但我认为我不能这样做,因为我要测试的方法返回 ADODB.Recordset。
为了创建另一个具有预期值的Recordset,我首先需要完全从头开始创建它:
// this probably doesn't actually compile, the actual conversion method
// doesn't exist yet and this is just to show the idea
var expected = new ADODB.RecordsetClass();
expected.Fields.Append("BoolValue", ADODB.DataTypeEnum.adBoolean);
expected.Fields.Append("Int32Value", ADODB.DataTypeEnum.adInteger);
expected.Fields.Append("StringValue", ADODB.DataTypeEnum.adVarWChar);
expected.AddNew();
expected.BoolValue = true;
expected.Int32Value = 1;
expected.StringValue = "foo";
expected.Update();
我也不喜欢这样,因为这基本上是对实际转换方法(被测方法)中一些代码的重复,这是测试中要避免的另一件事。
那么……我现在能做什么?
在这种特殊情况下,这种重复程度是否仍然可以接受,或者有更好的方法来测试它吗?
【问题讨论】:
-
这就是为什么它是单元测试的“艺术”而不是“科学”...
-
一个测试用例中的多个断言并不是邪恶的。每个测试用例应该只有一个断言is foolish的想法。
标签: c# unit-testing assert