Para corregir un error en una aplicación, modifiqué un método llamado postLogin
agregando una llamada a un método existente llamado getShoppingCart
.
Código
protected void postLogin() {
getShoppingCart();
}
Sin embargo, no estoy seguro de cuál es la mejor manera de escribir una prueba unitaria postLogin
.
Enfoque 1
Utilice verificar de Mockito para verificar simplemente que se llamó al método.
verify(mock).getShoppingCart();
Enfoque 2
Pruebe el efecto secundario de la llamada al método obteniendo el valor del carrito de compras del usuario.
AssertNotNull(user.getShoppingCart());
¿Es un enfoque mejor que el otro?
getShoppingCart()
método tenga efectos secundarios, no necesita probar que se llama. Si tiene efectos secundarios, debería cambiar su nombre porque losgetXXX()
métodos convencionales deberían ser idempotentes.getNextValue
? Podría decirse que alguien podría decir "No lo llames getter; cambia el nombre anextValue
", pero lo he vistogetNext
antes. Quizás un mejor ejemplo sería un objeto que representa un electrón; ¿Qué pasa cuando llamogetPosition
? O peor,getPosition(); getVelocity();
Respuestas:
Por lo general, preferiría el método 2.
¿Por qué? Porque desea
postLogin
cambiar algún estado de su sistema, pero la forma en que lo logra (y qué métodos llama internamente para esto) es simplemente un detalle de implementación, nada sobre lo que su prueba unitaria debe hacer suposiciones. Así que mejor haz tu prueba solo verificando el estado final.fuente
Cambiaría getShoppingCart por algo como initializeShoppingCart, el propósito del método debería ser claro para quien lo lea sin la necesidad de verificar qué hace el método y los efectos secundarios como este pueden causar un comportamiento sorprendente para los usuarios del método.
Si getShoppingCart está en otra clase y ya está probado en la unidad, usaría el enfoque 1; no es necesario volver a probar lo que ya está probado. En este caso, estamos seguros de que getShoppingCart funciona correctamente y solo queremos asegurarnos de que se llame desde postLogin, por lo que si alguien en el futuro elimina esta llamada, la prueba fallará.
Si getShoppingCart es un método privado que no se puede probar por sí solo, entonces usaría el enfoque 2, para asegurarme de que cuando se llame a postLogin, la funcionalidad deseada de getShoppingCart se realice como se esperaba.
fuente
Al probar una llamada de función (nula o no) que tiene un efecto secundario, es más completo probar que el efecto secundario no solo ocurre, sino verificar que el efecto secundario (salida del sistema o cambio de estado) sea el deseado.
fuente
No discutiré su diseño, pero en su caso elegiría el primer enfoque porque la prueba unitaria es para probar qué métodos hacen técnicamente independientemente de su trabajo en el dominio, es decir, ¿qué hace su método
postLogin
? Técnicamente llama,getShoppingCard
así que tienes que probar que realmente está llamandogetShoppingCard
, también crearía otra prueba paragetShoppingCard
probar lo que hace y si tiene efectos secundarios, lo comprobaré dentro de esa nueva prueba.fuente
Tienes un error en postLogin. Entonces, lo primero que debe hacer es crear una prueba unitaria que al llamar a postLogin sin el conjunto de información esperado "fallará".
A partir de la idea anterior, otra alternativa de las 2 propuestas es inyectar la información sobre el carrito de compras como parámetro. Si no tiene la información correcta, lanza una excepción no verificada. Esto dejará en claro que sin los detalles correctos, su método está condenado.
Esto requerirá un pequeño cambio en el que el cliente que llama al postLogin en este momento también debe pasar la información del carrito de compras. Para mí, esto sigue siendo coherente ahora que ves que están acoplados. Este acoplamiento lo realizará la persona que llama.
Entonces ni siquiera necesitaría probar getShoppingCart dentro de postLogin porque el método real bajo prueba es postLogin. Es el que tiene el error y el único que requiere una corrección y validación adecuadas. Con la dependencia inyectada, podrá probarla fácilmente en diferentes condiciones y confirmar que no se produce ningún error.
fuente