¿Hay alguna forma, usando Mockito, para burlarse de algunos métodos en una clase, pero no de otros?
Por ejemplo, en esta Stock
clase (ciertamente inventada) quiero burlarme de los valores getPrice()
y getQuantity()
devolverlos (como se muestra en el fragmento de prueba a continuación), pero quiero getValue()
que realice la multiplicación codificada en la Stock
clase
public class Stock {
private final double price;
private final int quantity;
Stock(double price, int quantity) {
this.price = price;
this.quantity = quantity;
}
public double getPrice() {
return price;
}
public int getQuantity() {
return quantity;
}
public double getValue() {
return getPrice() * getQuantity();
}
@Test
public void getValueTest() {
Stock stock = mock(Stock.class);
when(stock.getPrice()).thenReturn(100.00);
when(stock.getQuantity()).thenReturn(200);
double value = stock.getValue();
// Unfortunately the following assert fails, because the mock Stock getValue() method does not perform the Stock.getValue() calculation code.
assertEquals("Stock value not correct", 100.00*200, value, .00001);
}
Respuestas:
Para responder directamente a su pregunta, sí, puede burlarse de algunos métodos sin burlarse de otros. Esto se llama simulacro parcial . Consulte la documentación de Mockito sobre simulacros parciales para obtener más información.
Para su ejemplo, puede hacer algo como lo siguiente, en su prueba:
En ese caso, se burla de la implementación de cada método, a menos que se especifique
thenCallRealMethod()
en lawhen(..)
cláusula.También hay una posibilidad al revés con espía en lugar de simulacro :
En ese caso, toda la implementación del método es la real, excepto si ha definido un comportamiento simulado con
when(..)
.Hay un obstáculo importante cuando se usa
when(Object)
con espía como en el ejemplo anterior. Se llamará al método real (porquestock.getPrice()
se evalúa anteswhen(..)
en tiempo de ejecución). Esto puede ser un problema si su método contiene lógica a la que no debería llamarse. Puedes escribir el ejemplo anterior así:Otra posibilidad puede ser usar
org.mockito.Mockito.CALLS_REAL_METHODS
, como:Esto delega llamadas no contestadas a implementaciones reales.
Sin embargo, con su ejemplo, creo que todavía fallará, ya que la implementación de se
getValue()
basa enquantity
yprice
, en lugar degetQuantity()
ygetPrice()
, que es lo que se ha burlado.Otra posibilidad es evitar simulacros por completo:
fuente
Stock stock = spy(Stock.class);
Esto parece incorrecto, elspy
método parece aceptar solo objetos, no clases.doReturn(retval).when(spyObj).methodName(args)
ywhen(spyObj.methodName(args)).thenReturn(retval)
La burla parcial de una clase también es compatible a través de Spy in mockito
Consulte los documentos
1.10.19
y2.7.22
para obtener una explicación detallada.fuente
Según los documentos :
fuente
class NaughtyLinkedList extends LinkedList { public int size() { throw new RuntimeException("don't call me");} } @Test public void partialMockNaughtLinkedList(){ List mock = mock(NaughtyLinkedList.class, CALLS_REAL_METHODS); mock.add(new Object()); // this calls the real function when(mock.size()).thenReturn(2); // For whatever reason, this lines throws the RuntimeException. assertEquals(2,mock.size()); }
Esto no funciona Cualquiera sea la razón, cuando se ejecuta "cuándo", en realidad ejecuta el método que se supone que debe ser burlado. Código:Lo que quieres está de
org.mockito.Mockito.CALLS_REAL_METHODS
acuerdo con los documentos:Por lo tanto, su código debería verse así:
La llamada a
Stock stock = mock(Stock.class);
llamadasorg.mockito.Mockito.mock(Class<T>)
que se ve así:Los documentos del valor
RETURNS_DEFAULTS
dicen:fuente
withSettings()...
así? Parece queorg.mockito.internal.stubbing.answers.CallsRealMethods()
(por ejemplo) podría hacer el trabajo ... y el javadoc para esta clase específicamente dice que es para el uso de los simulacros parciales ...thenReturn
, ejecutará realmente el método (lo que podría causar problemas, aunque no en este ejemplo), por lo quedoReturn
es preferible en tal caso ...?La burla parcial con el método de espionaje de Mockito podría ser la solución a su problema, como ya se indicó en las respuestas anteriores. Hasta cierto punto, estoy de acuerdo en que, para su caso de uso concreto, puede ser más apropiado burlarse de la búsqueda de DB. Desde mi experiencia, esto no siempre es posible, al menos no sin otras soluciones, que consideraría muy engorroso o al menos frágil. Tenga en cuenta que la burla parcial no funciona con versiones aliadas de Mockito. Tienes uso al menos 1.8.0.
Hubiera escrito un comentario simple para la pregunta original en lugar de publicar esta respuesta, pero StackOverflow no lo permite.
Solo una cosa más: realmente no puedo entender que muchas veces una pregunta que se hace aquí reciba un comentario con "Por qué quieres hacer esto" sin al menos tratar de entender el problema. Especialmente cuando se trata de la necesidad de una burla parcial, realmente hay muchos casos de uso que podría imaginar dónde sería útil. Es por eso que los chicos de Mockito proporcionaron esa funcionalidad. Por supuesto, esta característica no debe ser utilizada en exceso. Pero cuando hablamos de configuraciones de casos de prueba que de otro modo no podrían establecerse de una manera muy complicada, se debe usar el espionaje.
fuente