unit-testing - dzone - mockito tutorial español
Mockito le da a UnfinishedVerificationException cuando parece correcto (3)
Parece que Mockito está lanzando una Excepción de verificación UnfinishedVerificationException
cuando creo que he hecho todo correctamente. Aquí está mi caso de prueba parcial:
HttpServletRequest req = mock(HttpServletRequest.class);
when(req.getHeader("Authorization")).thenReturn("foo");
HttpServletResponse res = mock(HttpServletResponse.class);
classUnderTest.doMethod(req, res); // Use the mock
verify(res, never());
verify(req).setAttribute(anyString(), anyObject());
Y aquí está la clase parcial y el método:
class ClassUnderTest extends AnotherClass {
@Override
public String doMethod(ServletRequest req, ServletRequest res) {
// etc.
return "someString";
}
}
Ignorando el hecho de que nunca deberías burlarte de las interfaces que no te pertenecen, ¿por qué Mockito me está dando el siguiente mensaje?
org.mockito.exceptions.misusing.UnfinishedVerificationException:
Missing method call for verify(mock) here:
-> at (redacted)
Example of correct verification:
verify(mock).doSomething()
Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
at [test method name and class redacted]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
... etc
Acabo de enterarme de esto y me causó mucha confusión.
Como David mencionó anteriormente, Mockito informa errores en la próxima llamada al método Mockito que puede no estar en el mismo método de prueba. Si bien el mensaje de excepción contiene una referencia al lugar real donde ocurrió el error, encuentro que las pruebas incorrectas no son productivas al proceso de prueba. Y cuanto más simples sean las pruebas, ¡más probable es que aparezca un error en la próxima prueba!
Aquí hay una solución fácil que asegurará que los errores aparezcan en el método de prueba correcto:
@After
public void validate() {
validateMockitoUsage();
}
De la documentación de Mockito aquí :
Mockito arroja excepciones si hace un uso incorrecto para saber si sus pruebas están escritas correctamente. El problema es que Mockito hace la validación la próxima vez que usa el marco (por ejemplo, la próxima vez que verifique, resguarde, llame simulacro, etc.). Pero a pesar de que la excepción podría arrojarse en la siguiente prueba, el mensaje de excepción contiene un elemento traza de pila navegable con la ubicación del defecto. Por lo tanto, puede hacer clic y buscar el lugar donde se utilizó mal Mockito.
A veces, sin embargo, es posible que desee validar el uso del marco de forma explícita. Por ejemplo, uno de los usuarios quería poner validateMockitoUsage () en su método @After para que él sepa de inmediato cuando utilizó mal Mockito. Sin él, él lo habría sabido antes de la próxima vez que utilizara el marco. Una ventaja más de tener validateMockitoUsage () en @After es que jUnit runner siempre fallará en el método de prueba con defecto, mientras que la validación ''próxima vez'' puede fallar en el próximo método de prueba. Pero a pesar de que JUnit podría reportar la siguiente prueba como roja, no te preocupes por eso y simplemente haz clic en el elemento de rastreo de pila navegable en el mensaje de excepción para ubicar instantáneamente el lugar donde usaste mal el mockito.
Tuve una excepción similar con la clase MyRepository
org.mockito.exceptions.misusing.UnfinishedVerificationException: Llamada al método faltante para verificar (simulacro) aquí: -> en MyRepository $$ FastClassBySpringCGLIB $$ de8d8358.invoke ()
Ejemplo de verificación correcta:
verify(mock).doSomething()
El problema se resolvió cuando creé la interfaz para MyRepository, y simulé la interfaz, pero no la implementación. Parece que Spring crea algunos proxies CGLIB y conduce a la excepción UnfinishedVerificationException.
Esto también podría ser causado si intentas verify
un método que espera argumentos primitivos con any()
:
Por ejemplo, si nuestro método tiene esta firma:
method(long l, String s);
Y si intentas verificarlo así, fallará con el mensaje antes mencionado:
verify(service).method(any(), anyString());
anyLong()
a anyLong()
y funcionará:
verify(service).method(anyLong(), anyString());