我正在研究TDD并在我当前的项目中进行实验。 我注意到我必须在测试中复制很多断言。 这是情况: 我有两个构造函数的Order类,第一个是默认的 第二个有三个参数
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类测试了这个方法,我需要使用相同的assert来检查Order是否已在CreateOrder服务中正确创建。
Assert.IsTrue(o.CustomerId == 5 && o.TypeId == 3 && amount == 500)
答案 0 :(得分: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(...);
}
如果在一个Assert语句中检查多个条件,则会使事情变得复杂。它会降低测试可读性,如果任何一个条件失败,可能很难找到原因。
答案 1 :(得分:3)
如果您需要为多个测试执行相同的对象验证,则将这些Asserts拆分为常用方法是减少重复的好方法。在上面的示例中,您可以使用一个名为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");
答案 2 :(得分:1)
是的,单元测试经常导致代码重复。但这种重复有价值。这个想法是,如果你用两种方式写同样的东西,你不可能两次都犯同样的错误。这意味着你会遇到很多愚蠢的错误。 (不可否认,其中一半是在您的单元测试代码中。)从代码中自动生成单元测试会导致所有代码重复,并且带来的好处更少。