测试也有代码味道
回看第一个测试用例的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"); } |