Acabo de empezar a usar objetos simulados (usando el mockito de Java) en mis pruebas recientes. Huelga decir que simplificaron la parte de configuración de las pruebas, y junto con Dependency Injection, yo diría que hizo que el código sea aún más robusto.Uso de simulacros en las pruebas
Sin embargo, me encontré tropezando en las pruebas contra la implementación en lugar de las especificaciones. Terminé estableciendo expectativas de que yo argumentaría que no es parte de las pruebas. En términos más técnicos, probaré la interacción entre el SUT (la clase bajo prueba) y sus colaboradores, ¡y esa dependencia no forma parte del contrato o la interfaz de la clase!
Considere que tiene lo siguiente: Cuando se trata de nodo XML, suponga que tiene un método, attributeWithDefault()
que devuelve el valor del atributo del nodo si está disponible, de lo contrario se devolverá un valor por defecto!
lo haría configuración de la prueba como la siguiente:
Element e = mock(Element.class);
when(e.getAttribute("attribute")).thenReturn("what");
when(e.getAttribute("other")).thenReturn(null);
assertEquals(attributeWithDefault(e, "attribute", "default"), "what");
assertEquals(attributeWithDefault(e, "other", "default"), "default");
Bueno, aquí no sólo no prueba que attributeWithDefault()
se adhiere a la especificación, pero también puso a prueba la aplicación, ya que obligaba a utilizar Element.getAttribute()
, en lugar de Element.getAttributeNode().getValue()
o Element.getAttributes().getNamedItem().getNodeValue()
, etc.
Supongo que lo estoy haciendo de la manera incorrecta, así que cualquier consejo sobre cómo puedo mejorar mi uso de los simulacros y las mejores prácticas será apreciado.
EDIT: lo que está mal con la prueba de
hice la suposición anterior de que la prueba es un mal estilo, aquí está mi razón de ser.
La especificación no especifica qué método se llama. Un cliente de la biblioteca no debería preocuparse por cómo se recupera el atributo, por ejemplo, siempre que se haga correctamente. El implementador debe tener libertad para acceder a cualquiera de los enfoques alternativos, de la forma que considere adecuada (con respecto al rendimiento, la coherencia, etc.). Es la especificación de
Element
que asegura que todos estos enfoques devuelven valores idénticos.No tiene sentido volver a factorizar
Element
en una sola interfaz de método congetElement()
(Go es bastante bueno acerca de esto en realidad). Para facilitar el uso, un cliente del método debería ser capaz de utilizar el estándarElement
en la biblioteca estándar. Tener interfaces y nuevas clases es simplemente una tontería, en mi humilde opinión, ya que hace que el código del cliente sea desagradable, y no vale la pena.Suponiendo que la especificación se mantiene como está y la prueba se mantiene como está, un nuevo desarrollador puede decidir refactorizar el código para usar un enfoque diferente de usar el estado y hacer que la prueba falle. Bueno, una prueba que falla cuando la implementación real se adhiere a la especificación es válida.
Tener un estado de exposición del colaborador en múltiples formatos es bastante común. Una especificación y la prueba no deben depender de qué enfoque particular se tome; ¡solo la implementación debería!
+1. Al igual que la forma en que aclaró la diferencia entre las pruebas de comportamiento (burlas) y estado (pruebas). – notnoop