如何编写综合的单元测试方案
作者:网络转载 发布时间:[ 2012/7/17 11:04:56 ] 推荐标签:
目前我们有8个测试了,这意味着当我们修改FirstName的属性值,我们要考虑会发生改变的每件事。但是这不算完。我们还需要确保没有别的会被意外改变。理论上说,这意味着更多的断言和相当数量的测试,但是,接下来我们采用取巧的方法,用ChangeAssert方法来替代HasErrors测试。
[TestMethod]
public void Person_FirstName_Set_Nothing_Unexpected_Changed()
{
var person = new Person("Adam", "Smith");
var changeAssert = new ChangeAssert(person);
person.FirstName = "Bob";
changeAssert.AssertOnlyChangesAre("FirstName", "FullName", "IsChanged");
}
ChangeAssert简单地通过映射获取对象的状态,因此,稍后你可以断言到除了你指出的几个具体属性其他的没变。
恭喜,你完成了你的第一个测试用例。完成一个,还有很多很多等着。
为什么说是"一个"测试用例?
那8个测试只是完成了覆盖FirstName属性从"Adam"修改成"Bob"这一个场景,在其他的值没有在错误状态、LastName不为null或空的情况下。让我们看看测试用例的完整清单:
●将FirstName值设置为"Adam"
●将FirstName值设置为null
●将FirstName 设为空串
●在LastName值为null的情况下,执行case1-3
●在LastName 为空串的情况下,执行case1-3
●在FirstName值以null开头的情况下,执行case1-5
●在FirstName值以空串开头的情况下,执行case1-5
目前我们看到了27个不同的场景。如果每个场景需要8个不同测试,仅仅为这一个属性,我们需要执行至多216个测试。根据这种思路,这是相当琐碎的一段代码。因此我们该怎么做呢?
测试也有代码味道
回看第一个测试用例的8个测试,它们都有同样的设置和运算。的不同是我们写的断言。在业界这个被称为一个代码味道。事实上,根据维基百科所列的这里应该有两个代码味道:
●Duplicated code
●重复的代码
●Excessively long identifiers
●过长的标识符
我们可以通过将断言合并到一个测试来轻松地消除这两个代码味道:
[TestMethod]
public void Person_FirstName_Set()
{
var person = new Person("Adam", "Smith");
var eventAssert = new PropertyChangedEventAssert(person);
var errorsChangedAssert = new ErrorsChangedEventAssert(person);
var changeAssert = new ChangeAssert(person);
person.FirstName = "Bob";
Assert.AreEqual("Bob", person.FirstName, "FirstName setter failed");
Assert.AreEqual("Bob Smith", person.FullName, "FullName not updated with FirstName changed");
Assert.IsTrue(person.IsChanged, "IsChanged flag was not set when FirstName changed");
eventAssert.Expect("IsChanged");
eventAssert.Expect("FirstName");
eventAssert.Expect("FullName");
errorsChangedAssert.ExpectNothing("Expected no ErrorsChanged events");
changeAssert.AssertOnlyChangesAre("FirstName", "FullName", "IsChanged");
}
知道什么导致测试失败很重要,因此我们在断言里添加失败的信息提示。
单元测试和代码重用
回看那27个测试用例,我们可以断定设置FirstName为null或者空串应该也需求同样的测试。因此我们可以扩展成:
[TestMethod]
public void Person_FirstName_Set_Empty()
{
Person_FirstName_Set_Invalid(String.Empty);
}
[TestMethod]
public void Person_FirstName_Set_Null()
{
Person_FirstName_Set_Invalid(null);
}
public void Person_FirstName_Set_Invalid(string firstName)
{
var person = new Person("Adam", "Smith");
var eventAssert = new PropertyChangedEventAssert(person);
var errorsChangedAssert = new ErrorsChangedEventAssert(person);
var changeAssert = new ChangeAssert(person);
Assert.IsFalse(person.IsChanged, "Test setup failed, IsChanged is not false");
Assert.AreEqual("Adam", person.FirstName, "Test setup failed, FirstName is not Adam");
Assert.AreEqual("Smith", person.LastName, "Test setup failed, LastName is not Smith");
person.FirstName = firstName;
Assert.AreEqual(firstName , person.FirstName, "FirstName setter failed");
Assert.AreEqual("Smith", person.FullName, "FullName not updated with FirstName changed");
Assert.IsTrue(person.IsChanged, "IsChanged flag was not set when FirstName changed");
eventAssert.Expect("IsChanged");
eventAssert.Expect("FirstName");
eventAssert.Expect("FullName");
Assert.IsTrue(person.HasErrors, "HasErrors should have remained false");
errorsChangedAssert.ExpectCountEquals(1, "Expected an ErrorsChanged event");
changeAssert.AssertOnlyChangesAre("FirstName", "FullName", "IsChanged", "HasErrors");
}
可以发现Person_FirstName_Set和Person_FirstName_Set_Invalid的差异很小,我们可以进一步试着通用化:
[TestMethod]
public void Person_FirstName_Set_Valid()
{
Person_FirstName_Set("Bob", false);
}
[TestMethod]
public void Person_FirstName_Set_Empty()
{
Person_FirstName_Set(String.Empty, true);
}
[TestMethod]
public void Person_FirstName_Set_Null()
{
Person_FirstName_Set(null, true);
}
public void Person_FirstName_Set(string firstName, bool shouldHaveErrors)
{
var person = new Person("Adam", "Smith");
var eventAssert = new PropertyChangedEventAssert(person);
var errorsChangedAssert = new ErrorsChangedEventAssert(person);
var changeAssert = new ChangeAssert(person);
Assert.IsFalse(person.IsChanged, "Test setup failed, IsChanged is not false");
Assert.AreEqual("Adam", person.FirstName, "Test setup failed, FirstName is not Adam");
Assert.AreEqual("Smith", person.LastName, "Test setup failed, LastName is not Smith");
person.FirstName = firstName;
Assert.AreEqual(firstName, person.FirstName, "FirstName setter failed");
Assert.AreEqual((firstName + " Smith")。Trim(), person.FullName, "FullName not updated with FirstName changed");
Assert.AreEqual(true, person.IsChanged, "IsChanged flag was not set when FirstName changed");
eventAssert.Expect("IsChanged");
eventAssert.Expect("FirstName");
eventAssert.Expect("FullName");
if (shouldHaveErrors)
{
Assert.IsTrue(person.HasErrors, "HasErrors should have remained false");
errorsChangedAssert.ExpectCountEquals(1, "Expected an ErrorsChanged event");
changeAssert.AssertOnlyChangesAre("FirstName", "FullName", "IsChanged", "HasErrors");
}
else
{
errorsChangedAssert.ExpectNothing("Expected no ErrorsChanged events");
changeAssert.AssertOnlyChangesAre("FirstName", "FullName", "IsChanged");
}
}
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南