Mockito: diferencia entre doReturn () y when ()

196

Actualmente estoy en el proceso de usar Mockito para simular mis objetos de capa de servicio en una aplicación Spring MVC en la que quiero probar mis métodos de controlador. Sin embargo, como he estado leyendo sobre los detalles de Mockito, he encontrado que los métodos doReturn(...).when(...)son equivalentes a when(...).thenReturn(...). Entonces, mi pregunta es ¿cuál es el punto de tener dos métodos que hacen lo mismo o cuál es la sutil diferencia entre doReturn(...).when(...)y when(...).thenReturn(...)?

Cualquier ayuda sería apreciada.

Pantera negra
fuente
1
El javadoc tiene algunos casos donde doReturn()es útil.
Sotirios Delimanolis
55
Creo que una de las principales diferencias es que doReturn (...). Cuando (..) es una versión anterior y no es segura y, por lo tanto, podemos usarla a veces cuando el compilador sigue quejándose de la conversión. When (..). ThenReturn (..) es mucho mejor en términos de tipo de seguridad
user2511882

Respuestas:

227

Las dos sintaxis para el apilamiento son aproximadamente equivalentes. Sin embargo, siempre se puede usar doReturn/whenpara tropezar; pero hay casos en los que no puedes usar when/thenReturn. Stubbing métodos vacíos es uno de esos. Otros incluyen el uso con espías Mockito y tropezar con el mismo método más de una vez.

Una cosa que when/thenReturnle da, que doReturn/whenno lo hace, es la verificación de tipo del valor que está devolviendo, en el momento de la compilación. Sin embargo, creo que esto casi no tiene valor: si tiene el tipo incorrecto, lo descubrirá tan pronto como ejecute su prueba.

Recomiendo encarecidamente solo usar doReturn/when. No tiene sentido aprender dos sintaxis cuando una lo hará.

Es posible que desee consultar mi respuesta en Forming Mockito "gramáticas" , una respuesta más detallada a una pregunta muy relacionada.

Dawood ibn Kareem
fuente
16
Estoy un poco en desacuerdo con David. A menudo me encuentro con situaciones en las que devuelvo el tipo incorrecto cuando lo uso doReturn/wheny paso los siguientes minutos averiguando qué salió mal. La comprobación de tipo de compilación se vuelve extremadamente útil con when/thenReturn.
Saket
11
Solo tenga en cuenta que Mockito recomienda que use el uso en when/thenReturnlugar de doReturn/when.
CodyEngel
2
@CodyEngel y no hay ninguna razón para tal recomendación, aparte de lo que describí en mis respuestas aquí y en stackoverflow.com/q/11462697 . Hace varios años, discutí esto con Brice Dutheil, quien actualmente es el desarrollador principal en funciones de Mockito, y hasta donde recuerdo, él está de acuerdo. Le pediré que publique un comentario aquí (no hay garantía de que lo haga).
Dawood ibn Kareem
18
El javadoc afirma que doReturn/whenes una compensación. El equipo no recomienda de una forma u otra, pero tenga en cuenta que el when/thenenfoque es más intuitivo, más legible y ofrece verificación de tiempo de compilación, es el enfoque que hizo que Mockito sea popular y fácil de usar, no olvide que cuando el código base es compartido por varias habilidades en su equipo; Sin embargo, tiene inconvenientes con respecto a los espías y los métodos nulos.
Brice
55
Solo para que conste: doReturn()tiene la gran desventaja de convertirse en codificación de llamadas de método al estilo YODA. Lo que luego viene escrito primero es decir. La mayoría de la gente lee de izquierda a derecha; así que ahora debes recordar constantemente invertir la lógica de retorno cuando en tu cabeza.
GhostCat
199

Ambos enfoques se comportan de manera diferente si usa un objeto espiado (anotado con @Spy) en lugar de un simulacro (anotado con @Mock):

  • when(...) thenReturn(...) realiza una llamada de método real justo antes de que se devuelva el valor especificado. Entonces, si el método llamado arroja una Excepción, debe lidiar con ella / burlarse, etc. Por supuesto, aún obtiene su resultado (lo que define thenReturn(...))

  • doReturn(...) when(...) no llama al método en absoluto .

Ejemplo:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

Prueba:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");
akcasoy
fuente
37
Este comportamiento solo funciona para objetos espiados, ya que son "envoltorios" de objetos reales. En el caso de los objetos burlados, no importa si es cuándo / luego Regresar o doReturn / cuándo. Los objetos burlados nunca llaman métodos reales.
Rafael Orágio
¿Podría dar más información por qué necesitamos usar esta funcionalidad? No veo un caso de uso práctico. La intención de la prueba es confirmar la corrección del código en diferentes casos de uso. Si el calll del método arroja una prueba de excepción debería arrojar una excepción, no devolver un valor
Gleichmut
@Gleichmut Este fue un escenario hipotético, donde muestro el uso / ventaja de doReturn. En una aplicación real, un método que sólo devuelve una excepción hace que, por supuesto, no tiene sentido .. pero hay métodos (probablemente no tan delgadas como éste), que puede lanzar excepciones en determinadas condiciones ..
akcasoy
1
Solo para aclarar: el método when (). ThenReturn () llama al método real (de un espía, no importa para los simulacros) solo una vez. Esto sucede en la línea en la que especifica el comportamiento simulado (cuando ( myClass.anotherMethodInClass () .thenRet ...). Después de eso, el método real nunca se vuelve a llamar. Quizás sea bueno saber si esperaba algo de lógica de decorador al leer la explicación arriba
Jonas
Esto no parece una ventaja doReturn(), parece un abuso de la biblioteca. El punto de espiar en lugar de pura burla es aprovechar las llamadas reales. También advierten contra el uso de espías como este: github.com/mockito/mockito/wiki/Using-Spies-(and-Fakes) (y recomiendan extender la clase y anular el método)
Matthew leyó el
13

Mockito javadoc parece decir por qué usar en doReturn()lugar de when() Use doReturn () en esas raras ocasiones en las que no puedes usar Mockito.when (Object).

Tenga en cuenta que Mockito.when (Object) siempre se recomienda para el apilamiento porque es seguro para el tipo de argumento y más legible (especialmente cuando se topan llamadas consecutivas).

Estas son esas raras ocasiones en que doReturn () es útil:

1. Cuando espiar objetos reales y llamar métodos reales a un espía trae efectos secundarios

List list = new LinkedList(); List spy = spy(list);

// Imposible: el método real se llama así que spy.get (0) arroja IndexOutOfBoundsException (la lista aún está vacía)

when(spy.get(0)).thenReturn("foo");

// Tienes que usar doReturn () para stubbing: doReturn("foo").when(spy).get(0);

2. Anulación de una excepción anterior:

when(mock.foo()).thenThrow(new RuntimeException());

// Imposible: el método foo () con excepción se llama así que se lanza RuntimeException. when(mock.foo()).thenReturn("bar");

// Tienes que usar doReturn () para stubbing:

doReturn("bar").when(mock).foo(); Los escenarios anteriores muestran una compensación de la elegante sintaxis de Mockito. Sin embargo, tenga en cuenta que los escenarios son muy raros. El espionaje debe ser esporádico y anular las excepciones es muy raro. Sin mencionar que, en general, anular el apisonamiento es un posible olor a código que señala demasiado apisonamiento.


fuente
6

Continuando con esta respuesta , existe otra diferencia de que si desea que su método devuelva diferentes valores, por ejemplo, cuando se llama por primera vez, se llama por segunda vez, etc., puede pasar valores, por ejemplo ...

PowerMockito.doReturn(false, false, true).when(SomeClass.class, "SomeMethod", Matchers.any(SomeClass.class));

Por lo tanto, devolverá falso cuando se llame al método en el mismo caso de prueba y luego devolverá falso nuevamente y, por último, verdadero.

ARIZONA_
fuente