2010-06-04 12 views
7

Estoy usando MS UnitTesting e intentando encontrar mi camino para escribir mis primeras pruebas unitarias. Parece que todas mis pruebas de unidad comienza con la creación de los mismos pocos objetos ...Creación de instancias de objetos en las clases de prueba

[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(); 
    ... 
} 

... etc

¿Es esto normal o tengo yo una idea equivocada? Creo que se suponía que todas las pruebas eran independientes, pero ¿cómo sería posible probar Dispatch() sin que eso implícitamente dependiera de CreateOrder y SetDeliveryAddress que ya está pasando?

Y la segunda parte de la pregunta, si el enfoque anterior se ve bien, ¿debería utilizar una fábrica o algo para crear una instancia de estos objetos en mi proyecto de prueba? No estoy seguro si un proyecto de prueba solo debe contener clases/métodos de prueba, o está bien agregar un grupo de ayudantes allí también.

Respuesta

8

Pareces estar en el camino correcto para mí. En muchas pruebas unitarias necesitará configurar el estado del objeto que está probando para poder probar una parte particular del comportamiento. Ayudará a agrupar las pruebas en clases cuando el comportamiento que está probando requiere una configuración similar, y utilizar métodos [TestInitialize] para reducir la duplicación de esa configuración.

por ejemplo:

[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(); 
} 

} 

Es bueno tener clases de ayuda en el proyecto de prueba - que debe ser el objetivo de hacer que se prueba un código bien factorizada como su código de producción.

2

Su primera pregunta tiene que ver con mocking and stubbing donde crea un pedido falso y una dirección creada a partir de la interfaz de cada clase. Así es como puedes probar el método Dispatch.

A continuación, puede afirmar que el método de envío hizo lo correcto comprobando qué pasó con sus objetos falsos (stub/mock).

En respuesta a la segunda parte de su pregunta; Es una muy buena idea tener métodos de fábrica e incluso jerarquías de clases para facilitar la escritura de las pruebas. Es tan importante estructurar las pruebas de una buena manera, como estructurar el código de producción.

+0

También me gustaría añadir que podría estar mejor con los constructores de prueba que las fábricas – Gutzofter

1

Creo que parte del problema puede estar en el diseño del objeto de su pedido. Tratar de escribir una prueba independiente solo para descubrir que depende de otras funciones generalmente sugiere que no están desacopladas adecuadamente. Un par de reglas generales que pueden ser apropiadas aquí:

Si Order.DeliveryAddress es simplemente un getter/setter simple, no se preocupe por probarlo. Eso es como tratar de demostrar que C# se comporta como debería. Hay poca ventaja al hacer esto. Por el contrario, hacer que su prueba de despacho dependa de que esta propiedad esté en buenas condiciones no es realmente una dependencia.

Sin embargo, si Order.DeliveryAddress realiza una lógica, como por ejemplo garantizar que la dirección solo se pueda modificar para las órdenes no despachadas, entonces es más complicado. Probablemente no desee tratar de enviar un pedido completo solo para probar que Order.DeliveryAddress ya no se pueda modificar posteriormente.

Invocando el Principio de Responsabilidad Individual (Ver 1 y 2) aquí diría que la clase de Orden ahora está haciendo demasiado. Es tanto el envío de pedidos como la aplicación de la integridad del estado del objeto de los datos del pedido.En ese caso, probablemente desee dividir la funcionalidad de despacho en un DispatcherService que simplemente toma un pedido y lo despacha, estableciendo un marcador IsDispatched en el pedido en el proceso.

Puede probar el comportamiento de DeliveryAddress simplemente configurando la propiedad IsDispatched de forma adecuada.

Un tercer enfoque (que es una especie de trampa, pero funciona bien en situaciones en las que intentas realizar pruebas sobre objetos legados) es subclase Pedir crear una clase TestableOrder que expone al accesorio de prueba la capacidad de jugar con el estado interno de la clase. En otras palabras, podría exponer un método MarkAsDispatched() que establecería el indicador IsDispatched interno de las clases y, por lo tanto, le permitirá probar que DeliveryAddress solo se puede establecer antes de marcarse como despachado.

Espero que ayude.

+0

"Si' Order.DeliveryAddress' es simplemente un getter/setter simple, entonces no se preocupe por probarlo. Eso es como tratar de demostrar que C# se comporta como debería. Hay pocas ventajas en hacer esto ". - Hmm - no estoy tan seguro de esto. Si por alguna razón un simple colocador no se comporta como debería (después de que todos los colocador es un código que puede, aunque sea poco probable, contener un error) le ahorrará ** mucho ** de tiempo si al menos considera la posibilidad que el problema podría ser el colocador. De lo contrario, puede comenzar a perseguir fantasmas y ver espectros :) Sólo mis dos centavos. – scherand

Cuestiones relacionadas