No discutiré sobre la legibilidad de las pruebas, el tamaño o las técnicas de prueba de estos marcos, Creo que son iguales, pero en un simple ejemplo, te mostraré la diferencia.
Teniendo en cuenta: Tenemos una clase que se encarga de almacenar algo en alguna parte:
public class Service {
public static final String PATH = "path";
public static final String NAME = "name";
public static final String CONTENT = "content";
private FileDao dao;
public void doSomething() {
dao.store(PATH, NAME, IOUtils.toInputStream(CONTENT));
}
public void setDao(FileDao dao) {
this.dao = dao;
}
}
y queremos probarlo:
Mockito:
public class ServiceMockitoTest {
private Service service;
@Mock
private FileDao dao;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
service = new Service();
service.setDao(dao);
}
@Test
public void testDoSomething() throws Exception {
// given
// when
service.doSomething();
// then
ArgumentCaptor<InputStream> captor = ArgumentCaptor.forClass(InputStream.class);
Mockito.verify(dao, times(1)).store(eq(Service.PATH), eq(Service.NAME), captor.capture());
assertThat(Service.CONTENT, is(IOUtils.toString(captor.getValue())));
}
}
EasyMock:
public class ServiceEasyMockTest {
private Service service;
private FileDao dao;
@Before
public void setUp() {
dao = EasyMock.createNiceMock(FileDao.class);
service = new Service();
service.setDao(dao);
}
@Test
public void testDoSomething() throws Exception {
// given
Capture<InputStream> captured = new Capture<InputStream>();
dao.store(eq(Service.PATH), eq(Service.NAME), capture(captured));
replay(dao);
// when
service.doSomething();
// then
assertThat(Service.CONTENT, is(IOUtils.toString(captured.getValue())));
verify(dao);
}
}
Como puede ver, ambas pruebas son bastante iguales y ambas pasan. Ahora, imaginemos que alguien más cambió la implementación del Servicio e intentó ejecutar las pruebas.
aplicación
nuevo servicio:
dao.store(PATH + separator, NAME, IOUtils.toInputStream(CONTENT));
separador se añadió al final del PATH constante
Cómo las pruebas de resultados se verá así en este momento? En primer lugar las dos pruebas fallará, pero con diferentes mensajes de error:
EasyMock:
java.lang.AssertionError: Nothing captured yet
at org.easymock.Capture.getValue(Capture.java:78)
at ServiceEasyMockTest.testDoSomething(ServiceEasyMockTest.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
Mockito:
Argument(s) are different! Wanted:
dao.store(
"path",
"name",
<Capturing argument>
);
-> at ServiceMockitoTest.testDoSomething(ServiceMockitoTest.java:34)
Actual invocation has different arguments:
dao.store(
"path\",
"name",
[email protected]
);
-> at Service.doSomething(Service.java:13)
¿Qué pasó en la prueba EasyMock, qué resultado no fue capturado? ¿El método de la tienda no se ejecutó, pero espere un minuto, fue, por qué EasyMock nos miente?
Es porque EasyMock mezcla dos responsabilidades en una sola línea: el troceo y la verificación. Es por eso que cuando algo está mal, es difícil entender qué parte está causando el fracaso.
Por supuesto que usted puede decirme - simplemente cambie la prueba y mueva la verificación antes de la aserción. Wow, ¿hablas en serio, los desarrolladores deben tener en cuenta algún orden mágico inspirado por el marco burlón?
Por cierto, no va a ayudar:
java.lang.AssertionError:
Expectation failure on verify:
store("path", "name", capture(Nothing captured yet)): expected: 1, actual: 0
at org.easymock.internal.MocksControl.verify(MocksControl.java:111)
at org.easymock.classextension.EasyMock.verify(EasyMock.java:211)
Aún así, me está diciendo que el método no se ha ejecutado, pero era, sólo que con otros parámetros.
¿Por qué Mockito es mejor? Este marco no combina dos responsabilidades en un solo lugar y cuando sus pruebas fallarán, comprenderá fácilmente por qué.
Sí, he estado pensando lo mismo: con Mockito (y Unitils Mock, una API de burla similar) es mucho más fácil de escribir pruebas que se siguen para pasar alegremente cuando no deberían hacerlo. Sospecho que esta puede ser la razón principal por la que las API tipo Mockito, que facilitan la creación de pruebas excesivamente "flojas", a menudo se consideran "más fáciles". –
Me interesaría ver un ejemplo que contrasta estos 2 enfoques ... – Armand