2011-02-08 90 views
3

我正在研究TDD并在我当前的项目中进行实验。 我注意到我必须在测试中复制很多断言。 这里的情况: 我Order类有两个构造函数第一个是默认的, 第二个有三个PARAMS单元测试声明重复

Order(int customerId, int typeId, decimal amount) 

在OrderTests类,我检查作业运作良好

Assert.IsTrue(o.CustomerId == 5 && o.TypeId == 3 && amount == 500) 

由于订单创建是复杂的过程,因此我有订单服务类和以下创建订单方法。

Order CreateOrder(int cusotmerId, int typeId, int amount, moreParams...) 

OrderServiceTests类有这个方法测试,我需要用相同的断言检查订单已在CreateOrder服务正确创建。

Assert.IsTrue(o.CustomerId == 5 && o.TypeId == 3 && amount == 500) 
  1. 是否确定有这样的测试重复?
  2. 在测试中提取具有相同断言的方法是否有意义,因为有时数字或重复的断言可能多于一个?或者这种方法提取使得测试不可读?
+0

据我所知,你试图测试一个对象的创建。你为什么需要这样做?有没有复杂的逻辑? – Andrey

+0

是的,正如我写的,它是创建对象图的复杂过程 – Danil

+0

假设Order不是一个纯粹的值对象/数据结构(在这种情况下,它可能太小而无法/失败):你可以写一个助手方法AreAttributesEqual expectedOrder,actualOrder,listOfAttributesToCompare)'它使用反射。如果你想总是比较所有的属性,它就更简单了。 – Gishu

回答

4

如果您有多种创建对象的方式,您可能需要测试每个创建方法(即参数化构造函数以及工厂方法)的对象状态。因此重复这些断言是有意义的。

如果您在生产代码中但在测试中发现重复,则在进行测试通过后重新进行重构(总是记住曼陀罗:红绿重构),那么应该通过例如删除它。使用Extract Method重构。

[TestMethod] 
public void if_parametrized_ctor_is_called_then_state_should_be_accordingly { 
    var order = new Order(customerId, ...); 
    ObjectPropertiesShouldBeSetTo(order, customerId, ...); 
} 

[TestMethod] 
public void if_factory_method_is_called_then_state_should_be_accordingly { 
    var order = myFactory.CreateOrder(customerId, ...); 
    ObjectPropertiesShouldBeSetTo(order, customerId, ...); 
} 

// Extracted to remove code duplication 
public void ObjectPropertiesShouldBeSetTo(Order order, int customerId, ...) { 
    Assert.AreEqual(customerId, order.CustomerId); 
    Assert.AreEqual(...); 
} 

如果一个断言语句中检查多个条件,在你的榜样它复杂的事情。它降低了测试可读性,并且如果任何一个条件失败,可能很难找到原因。

1

是的,单元测试经常会导致代码重复。但是这种重复是有价值的。这个想法是,如果你用两种方式写同样的东西,你不可能在两次都犯同样的错误。这意味着你会遇到很多愚蠢的错误。 (当然,其中有一半是在你的单元测试代码中。)从你的代码中自动生成单元测试会导致所有的代码重复,并且减少了好处。

3

如果您需要为多个测试执行相同的对象验证,将这些断言拆分为常用方法是减少重复的好方法。在你上面的例子中,你可以有一个名为AssertObjectIsValid的方法,并将通用代码移到那里。

关于您的示例Assert的另一件事。在单个Assert中组合多个检查使得从故障中确定哪个属性出错是更困难的。如果拆分到这些独立的主张,并为每个提供的消息,就会使跟踪误差容易得多(特别是如果你使用持续集成服务器,如CruiseControl.Net。)修改你的例子:

Assert.IsTrue(o.CustomerID == 5, "CustomerID doesn't match expected"); 
Assert.IsTrue(o.TypeId == 3, "TypeID doesn't match expected"); 
Assert.IsTrue(amount == 500, "Amount doesn't match expected"); 
+3

我还补充说,使用Assert.IsEqual(5, o.CustomerID);导致断言失败的可读性更好,因为它会明确告诉你什么CustomerID设置为,而不是使用Assert.IsTrue() bcarlso

+0

嗯,我已经在一个断言中写了几个检查来减少断言的数量。在其他情况下,我只需创建8个断言(因为它将状态更改历史记录添加到内部历史记录集合中)。嗯,也许这不是一个问题,有8个断言。 – Danil

+0

@bcarlso - 使用IsEqual的好处。 @Danil - 如果你有很多事情需要验证,那么有大量的断言是很好的。将一组断言组合成一个常用的方法有时有助于保持行数的减少。 – Pedro

相关问题