您好,欢迎访问三七文档
当前位置:首页 > 中学教育 > 高中教育 > 如何编写综合的单元测试方案
每个用例编写一到二个断言是单元测试最佳实践的常见内容.那些这么认为的是极少和只展示一个单元测试的人。因此如果你采纳他们的建议,为一个很小的运算你都需要大量的单元测试去保证质量。这篇文章意图通过例子展示,一个测试用例多个断言是有必要和有价值的。Person这个对象在数据绑定场景中经常出现,我们来看下。测试FirstName第一个来测试FirstName这个属性的设置,开始如下:[TestMethod]123456javakeywordpublicvoidPerson_FirstName_Set(){varperson=newPerson(Adam,Smith);person.FirstName=Bob;Assert.AreEqual(Bob,person.FirstName);}接下来我们来测试FirstName的改变通知。[TestMethod]1234567publicvoidPerson_FirstName_Set_PropertyChanged(){varperson=newPerson(Adam,Smith);vareventAssert=newGranite.Testing.PropertyChangedEventAssert(person);person.FirstName=Bob;eventAssert.Expect(FirstName);}当我们执行这个测试时,会得到一个失败提示信息“期望的属性名‘FirstName’,但接收到的是’IsChanged’”。显然,设置FirstName的属性触发了“IsChanged”标记,我们需要把它考虑在内。因此我们把它加入:[TestMethod]12345678publicvoidPerson_FirstName_Set_PropertyChanged(){varperson=newPerson(Adam,Smith);vareventAssert=newGranite.Testing.PropertyChangedEventAssert(person);person.FirstName=Bob;eventAssert.SkipEvent();//thiswasIsChangedeventAssert.Expect(FirstName);}鉴于以上两个测试,我们考虑当FirstName被修改时还有其他什么属性会改变。查看API,IsChanged和FullName属性会变化。[TestMethod]123456publicvoidPerson_FullName_Changed_By_Setting_FirstName(){varperson=newPerson(Adam,Smith);person.FirstName=Bob;Assert.AreEqual(BobSmith,person.FullName);}[TestMethod]123456publicvoidPerson_IsChanged_Changed_By_Setting_FirstName(){varperson=newPerson(Adam,Smith);person.FirstName=Bob;Assert.IsTrue(person.IsChanged);}当然,如果这些属性改变了,我们需要获取到属性改变通知:[TestMethod]1234567publicvoidPerson_IsChanged_Property_Change_Notification_By_Setting_FirstName(){varperson=newPerson(Adam,Smith);vareventAssert=newPropertyChangedEventAssert(person);person.FirstName=Bob;eventAssert.Expect(IsChanged);}[TestMethod]123456789publicvoidPerson_FullName_Property_Change_Notification_By_Setting_FirstName(){varperson=newPerson(Adam,Smith);vareventAssert=newPropertyChangedEventAssert(person);person.FirstName=Bob;eventAssert.SkipEvent();//thiswasIsChangedeventAssert.SkipEvent();//thiswasFirstNameeventAssert.Expect(FullName);}接下来两个测试针对HasErrors这个属性和ErrorsChanged事件。[TestMethod]123456publicvoidPerson_FirstName_Set_HasErrorsIsFalse(){varperson=newPerson(Adam,Smith);person.FirstName=Bob;Assert.IsFalse(person.HasErrors);}[TestMethod]1234567publicvoidPerson_FirstName_Set_ErrorsChanged_Did_Not_Fire(){varperson=newPerson(Adam,Smith);varerrorsChangedAssert=newErrorsChangedEventAssert(person);person.FirstName=Bob;errorsChangedAssert.ExpectNothing();}目前我们有8个测试了,这意味着当我们修改FirstName的属性值,我们要考虑会发生改变的每件事。但是这不算完。我们还需要确保没有别的会被意外改变。理论上说,这意味着更多的断言和相当数量的测试,但是,接下来我们采用取巧的方法,用ChangeAssert方法来替代HasErrors测试。[TestMethod]1234567publicvoidPerson_FirstName_Set_Nothing_Unexpected_Changed(){varperson=newPerson(Adam,Smith);varchangeAssert=newChangeAssert(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个测试,它们都有同样的设置和运算。唯一的不同是我们写的断言。在业界这个被称为一个代码味道。事实上,根据维基百科所列的这里应该有两个代码味道:●Duplicatedcode●重复的代码●Excessivelylongidentifiers●过长的标识符我们可以通过将断言合并到一个测试来轻松地消除这两个代码味道:[TestMethod]12345678910111213141516publicvoidPerson_FirstName_Set(){varperson=newPerson(Adam,Smith);vareventAssert=newPropertyChangedEventAssert(person);varerrorsChangedAssert=newErrorsChangedEventAssert(person);varchangeAssert=newChangeAssert(person);person.FirstName=Bob;Assert.AreEqual(Bob,person.FirstName,FirstNamesetterfailed);Assert.AreEqual(BobSmith,person.FullName,FullNamenotupdatedwithFirstNamechanged);Assert.IsTrue(person.IsChanged,IsChangedflagwasnotsetwhenFirstNamechanged);eventAssert.Expect(IsChanged);eventAssert.Expect(FirstName);eventAssert.Expect(FullName);errorsChangedAssert.ExpectNothing(ExpectednoErrorsChangedevents);changeAssert.AssertOnlyChangesAre(FirstName,FullName,IsChanged);}知道什么导致测试失败很重要,因此我们在断言里添加失败的信息提示。单元测试和代码重用回看那27个测试用例,我们可以断定设置FirstName为null或者空串应该也需求同样的测试。因此我们可以扩展成:[TestMethod]1234publicvoidPerson_FirstName_Set_Empty(){Person_FirstName_Set_Invalid(String.Empty);}[TestMethod]123456789101112131415161718192021222324publicvoidPerson_FirstName_Set_Null(){Person_FirstName_Set_Invalid(null);}publicvoidPerson_FirstName_Set_Invalid(stringfirstName){varperson=newPerson(Adam,Smith);vareventAssert=newPropertyChangedEventAssert(person);varerrorsChangedAssert=newErrorsChangedEventAssert(person);varchangeAssert=newChangeAssert(person);Assert.IsFalse(person.IsChanged,Testsetupfailed,IsChangedisnotfalse);Assert.AreEqual(Adam,person.FirstName,Testsetupfailed,FirstNameisnotAdam);Assert.AreEqual(Smith,person.LastName,Testsetupfailed,LastNameisnotSmith);person.FirstName=firstName;Assert.AreEqual(firstName,person.FirstName,FirstNamesetterfailed);Assert.AreEqual(Smith,person.FullName,Fu
本文标题:如何编写综合的单元测试方案
链接地址:https://www.777doc.com/doc-6369003 .html