2010-06-04 204 views
7

我正在使用MS UnitTesting并试图找到自己的方式来编写我的第一个单元测试。这似乎是我所有的单元测试开始与创建相同的几个对象......测试类中的对象实例化

[TestMethod] 
CanCreateOrder() 
{ 
    <create an order> 
    ... 
} 


[TestMethod] 
CanSetOrderDeliveryAddress() 
{ 
    <create an order> 
    <create an address> 
    order.DeliveryAddress = address; 
    ... 
} 

[TestMethod] 
CanDispatchAnOrder() 
{ 
    <create an order> 
    <create an address> 
    order.DeliveryAddress = address; 
    order.Dispatch(); 
    ... 
} 

...等

这是正常的,或者已经我得到了错误的想法?我认为每个测试都应该是独立的,但是如何测试Dispatch()而不隐含依赖CreateOrderSetDeliveryAddress已经通过?

问题的第二部分,如果上述方法看起来不错,我应该使用工厂还是其他方法在我的测试项目中实例化这些对象?我不确定一个测试项目是否应该只包含测试类/方法,或者也可以在其中添加一些助手。

回答

8

你似乎在正确的轨道上给我。在很多单元测试中,您需要设置您正在测试的对象的状态,以便能够测试某个特定部分的行为。 当您正在测试的bahaviour需要类似的设置并使用[TestInitialize]方法来减少该设置的重复时,它将有助于在类中对测试进行分组。

如:

[TestClass] 
public class WhenReadyToDispatch{ 

private Order order; 

[TestInitialize] 
public void Initialize 
{ 
    order = <create an order> 
    order.DeliveryAddress = <create an address> 
} 

[TestMethod] 
CanChangeOrderDeliveryAddress() 
{ 

    order.DeliveryAddress = address; 
} 

[TestMethod] 
CanDispatchAnOrder() 
{ 
    order.Dispatch(); 
} 

} 

它的优良有测试项目的辅助类 - 你应该旨在让您测试代码以及​​分解为你的产品代码。

2

您的第一个问题是与mocking and stubbing一起处理您创建从每个类的接口创建的虚假订单和地址。这就是你如何才能测试Dispatch方法。

然后,您可以断言调度方法通过检查您的虚假(存根/模拟)对象发生了什么来做正确的事情。

回答问题的第二部分; 为了使编写测试变得更简单,建立工厂方法甚至类层次结构是一个非常好的主意。以一种好的方式来构建测试同样重要,因为它是构造生产代码。

+0

我还想补充说,你可能比测试构建者更适合工厂使用 – Gutzofter 2010-06-08 01:56:13

1

我认为你的问题的一部分可能是你的订单对象的设计。试图编写一个独立测试只会发现它依赖于其他功能通常表明它们没有充分分离。一些经验法则可能适用于这里:

如果Order.DeliveryAddress只是一个简单的getter/setter,那么不用担心测试它。这就像试图证明C#的行为应该如此。这样做没有什么优势。相反,让您的调度程序测试依赖于此属性处于正常工作状态并不是真正的依赖。

但是,如果Order.DeliveryAddress正在执行逻辑,例如确保地址只能修改为未调度的订单,则它会更复杂。您可能不想尝试分派整个订单,以便测试Order.DeliveryAddress之后不再可修改。

调用单一责任原则(请参阅12)这里会说Order类现在做得太多了。它既调度订单,又强制执行订单数据的对象状态完整性。在这种情况下,您可能希望将调度功能拆分为DispatcherService,该调度程序只需执行一个命令并将其分派,并在流程中的订单上设置IsDispatched标志。

然后,您可以通过适当地设置IsDispatched属性来测试DeliveryAddress行为。

第三种方法(这是一种欺骗,但在您试图对传统对象进行一些测试的情况下运行良好)是对Order进行子类化以创建一个TestableOrder类,该类可向测试工具提供修补班级的内部状态。换句话说,它可能会公开一个MarkAsDispatched()方法,该方法将设置类内部的IsDispatched标志,从而允许您测试DeliveryAddress仅在被标记为分派之前可设置。

希望有所帮助。

+0

“如果'Order.DeliveryAddress'只是一个简单的getter/setter,那么就不用担心测试它。这就像试图证明C#的行为应该是这样,这样做没有什么优势。“ - 嗯 - 对此不太确定。如果无论出于何种原因,一个简单的setter不会像它应该那样工作(毕竟每个setter都是可以的,即使不太可能,也会包含一个错误),如果至少考虑到可能性,它会为您节省很多时间**问题可能是二传手。否则,你开始可能会开始追鬼,看到幽灵:) 只是我的两美分。 – scherand 2010-06-04 15:03:25