2011-07-12 17 views
12

Tengo un montón de métodos en mi capa de servicios de aplicaciones que están haciendo cosas como esta:Capa de servicio de aplicación: ¿Pruebas unitarias, pruebas de integración o ambas?

public void Execute(PlaceOrderOnHoldCommand command) 
{ 
    var order = _repository.Load(command.OrderId); 
    order.PlaceOnHold(); 
    _repository.Save(order); 
} 

Y en la actualidad, tengo un montón de pruebas unitarias como esto:

[Test] 
public void PlaceOrderOnHold_LoadsOrderFromRepository() 
{ 
    var repository = new Mock<IOrderRepository>(); 
    const int orderId = 1; 
    var order = new Mock<IOrder>(); 
    repository.Setup(r => r.Load(orderId)).Returns(order.Object); 

    var command = new PlaceOrderOnHoldCommand(orderId); 
    var service = new OrderService(repository.Object); 
    service.Execute(command); 

    repository.Verify(r => r.Load(It.Is<int>(x => x == orderId)), Times.Exactly(1)); 
} 

[Test] 
public void PlaceOrderOnHold_CallsPlaceOnHold() 
{ 
      /* blah blah */ 
} 

[Test] 
public void PlaceOrderOnHold_SavesOrderToRepository() 
{ 
      /* blah blah */ 
} 

Parece discutible si estas pruebas unitarias agregan valor que vale la pena el esfuerzo. Sin embargo, estoy bastante seguro de que la capa de servicio de la aplicación debería ser probada de integración.

caso de que la capa de servicio de aplicación se va a ensayar a este nivel de granularidad, o son pruebas de integración suficiente?

Respuesta

8

Exactamente: ¡es discutible! Es realmente bueno que sopeses el gasto/esfuerzo de escribir y mantener tu prueba en comparación con el valor que te dará, y esa es exactamente la consideración que debes tener en cada prueba que escribas. A menudo veo pruebas escritas con el objetivo de realizar pruebas y, por lo tanto, solo agrego lastre a la base del código.

Como norma, generalmente considero que quiero una prueba de integración completa de cada escenario de éxito/caso de uso importante. Otras pruebas que escribiré son partes del código que son que pueden romperse con cambios futuros o que se han roto en el pasado. Y definitivamente eso no es todo código. Ahí es donde entran en juego tu criterio y tu percepción del sistema y los requisitos.

Suponiendo que tiene una prueba (de integración) para service.Execute(placeOrderOnHoldCommand), no estoy seguro si agrega valor para probar si el servicio carga una orden del repositorio exactamente una vez. ¡Pero podría ser!Por ejemplo, cuando su servicio tenía un error desagradable que golpearía el repositorio diez veces para una sola orden, lo que ocasionaba problemas de rendimiento (solo inventarlo). En ese caso, cambiaría el nombre de la prueba a PlaceOrderOnHold_LoadsOrderFromRepositoryExactlyOnce().

Así que para cada prueba debes decidir por ti mismo ... espero que eso ayude.

Notas:

  1. las pruebas que demuestren puede ser perfectamente válido y mirar bien escrito.

  2. Sus métodos de secuencia de prueba parecen estar inspirados en la forma en que actualmente se implementa el método Execute(...). Cuando estructura su prueba de esta manera, es posible que se esté atando a una implementación específica. De esta manera, las pruebas pueden hacer que sea más difícil cambiar, asegúrese de que solo está probando el comportamiento externo importante de su clase.

+1

Estos son realmente buenos puntos que mencionas Creo que primero escribiré las pruebas de integración *, luego veré qué posibles pruebas de valor unitario aportarían (por ejemplo, que InvalidOperationExceptions se lanza cuando se proporciona una identificación de orden incorrecta). Y también menciona un buen punto acerca de probar la implementación con demasiada fuerza: el punto son las entradas y salidas, no la implementación. –

4

que suelo escribir una sola prueba de integración del escenario principal. Por escenario primario me refiero a la ruta exitosa de todo el código que se prueba. Luego escribo pruebas unitarias de todos los otros escenarios, como verificar todos los casos en un interruptor, probar excepciones, etc.

Creo que es importante tener ambos y sí, es posible probarlo todo solo con pruebas de integración, pero eso hace que las pruebas sean de larga duración y más difíciles de depurar. En promedio, creo que tengo 10 pruebas unitarias por prueba de integración.

No me molesto en probar los métodos con líneas simples a menos que ocurra algo parecido a una lógica lógica en esa línea.

Actualización: Para dejarlo en claro, porque estoy haciendo un desarrollo basado en pruebas Siempre escribo las pruebas de la unidad primero y normalmente hago la prueba de integración al final.

10

me gustaría escribir una prueba de unidad a pesar de ser también una prueba de integración. Sin embargo, probablemente haría la prueba mucho más simple al eliminar el marco de burla, escribir mi propio simulacro simple y luego combinar todas esas pruebas para verificar que el orden en el repositorio de simulacro estaba en espera.

[Test] 
public void PlaceOrderOnHold_LoadsOrderFromRepository() 
{ 
    const int orderId = 1; 
    var repository = new MyMockRepository(); 
    repository.save(new MyMockOrder(orderId));  
    var command = new PlaceOrderOnHoldCommand(orderId); 
    var service = new OrderService(repository); 
    service.Execute(command); 
    Assert.IsTrue(repository.getOrder(orderId).isOnHold()); 
} 

Realmente no hay necesidad de verificar para asegurarse de que se carga y/o se guarda. En su lugar, me aseguraría de que la única manera en que MyMockRepository devolverá el pedido actualizado es si se llama a load y save.

Este tipo de simplificación es una de las razones por las que no me suelen recurrir a los marcos burlones. Me parece que tienes mucho mejor control sobre tus pruebas, y es mucho más fácil escribirlas, si escribes tus propios simulacros.

+1

Interesante tomar Uncle Bob. Pareció que terminó bastante abruptamente, aunque :) –

+0

pero probablemente también haya una prueba para 'Order.PlaceOnHold()'. Entonces, si ahora decide que el pedido con ID 1 no se puede poner en espera, tiene 2 pruebas para reparar – driushkin

+0

@unclebob ¡Gracias! Voy a tomar esto en consideración. @driushkin Hay una prueba para 'Order.PlaceOnHold()' seguro. Sin embargo, si una orden se puede poner en espera es completamente la preocupación de la implementación de la clase de orden real - la simulación no tendría ningún efecto sobre lo que debería suceder en el método de servicio. –

Cuestiones relacionadas