2011-12-14 18 views
19

tengo un constructor:Cómo burlarse de un constructor con Mockito

class Builder{ 
    private String name; 
    private String address; 
    public Builder setName(String name){ 
     this.name = name; 
     return this; 
    } 
    public Builder setAddress(String address){ 
     this.address = address; 
     return this; 
    } 

} 

que imita el constructor en la voluntad Mockito me da nulo para cada método. Entonces, ¿hay alguna manera fácil de obtener el generador de retorno en cada llamada de función, sin burlarse de cada función utilizando when().thenReturn.

+2

¿Realmente necesitas burlarte de esto? No parece el tipo de dependencia que vale la pena burlarse. Parece un tipo de clase de "datos", en lugar de un tipo de clase de "servicio". Raramente encuentro que es útil hacer clases donde no hay mucho comportamiento real. –

+1

Es solo un ejemplo, el verdadero constructor es un poco más complejo y simplemente no es necesario probarlo en este caso. –

+1

¿Puedes separarlos para que * tengas * un "constructor tonto" (que no necesita burla) y luego la parte del servicio que * necesita * burla? –

Respuesta

8

Puede usar RETURN_DEEP_STUBS para simular una API de encadenamiento.

Si conoce el orden exacto de su constructor se llama, aquí está un ejemplo de cómo se usa:

Builder b = Mockito.mock(Builder.class, RETURNS_DEEP_STUBS); 
when(b.setName("a name").setAddress("an address")).thenReturn(b); 
assert b.setName("a name").setAddress("an address") == b; // this passes 

Desafortunadamente esto no le dará una forma genérica de burla "Todas las diversas constructor métodos "para que siempre devuelvan esto, vea la otra respuesta es que lo necesita".

+2

También tenga en cuenta que si obtiene el código auxiliar profundo "incorrecto" y emite el resultado, le dará algunos mensajes de aspecto extraño, posiblemente como 'java.lang.ClassCastException: org.mockito.internal.creation.jmock.ClassImposterizer $ ClassWithSuperclassToWorkAroundCglibBug $$ EnhancerByMockitoWithCGLIB $$ 851828bd no se puede convertir a ... ' – rogerdpack

34

El problema con el uso de RETURN_DEEP_STUBS es que obtendrá una simulación diferente cada vez que llame a un método. Creo que a partir de su pregunta, quiere utilizar una respuesta predeterminada que realmente devuelve el simulacro en el que se llamó, para cada método que tenga el tipo de devolución correcto. Esto podría parecerse a lo siguiente. Tenga en cuenta que no he probado esto, por lo que puede contener errores tipográficos, pero espero que la intención sea clara en cualquier caso.

import static org.mockito.Mockito.RETURNS_DEFAULTS; 
import org.mockito.invocation.InvocationOnMock; 
import org.mockito.stubbing.Answer; 

public class SelfReturningAnswer implements Answer<Object>{ 

    public Object answer(InvocationOnMock invocation) throws Throwable { 
     Object mock = invocation.getMock(); 
     if(invocation.getMethod().getReturnType().isInstance(mock)){ 
      return mock; 
     } 
     else{ 
      return RETURNS_DEFAULTS.answer(invocation); 
     } 
    } 
} 

Luego, cuando cree su simulacro, especifique esto como su respuesta predeterminada. Esto hará que su simulacro regrese de cada método que pueda; pero se comportará como un simulacro común cuando llamas a un método cuyo tipo de devolución es incorrecto para el simulacro.

Crear su maqueta como esto

Builder mockBuilder = mock(Builder.class, new SelfReturningAnswer()); 

o cree una constante para esta clase y escribir algo como

@Mock(answer = SELF_RETURNING) private Builder mockBuilder; 

Espero que ayude.

+0

¿Estás seguro? Yo uso'verify' en mi simulacro de stubbed profundo y pasa las pruebas. Por lo tanto, debe devolver la misma instancia cada vez que utilizo un método de compilación. –

+1

Sí, estoy absolutamente seguro.Escribí una prueba para tu clase de Constructor, como la anterior, donde hice una prueba con RETURNS_DEEP_STUBS, luego llamé a setAddress y setName. Mi prueba afirmó que los dos simulacros devueltos por las dos llamadas al método eran diferentes. Mi prueba pasó. –

+0

Mi prueba está en http://pastebin.com/JNPrn4ng –

12

A partir de Mockito 2.0 (beta), hay una nueva respuesta predeterminada para RETURNS_SELF que se comporta de forma casi idéntica a David Wallace's answer. Ejemplo de los documentos Mockito:

@Test 
public void use_full_builder_with_terminating_method() { 
    HttpBuilder builder = mock(HttpBuilder.class, RETURNS_SELF); 
    HttpRequesterWithHeaders requester = new HttpRequesterWithHeaders(builder); 
    String response = "StatusCode: 200"; 

    when(builder.request()).thenReturn(response); 

    assertThat(requester.request("URI")).isEqualTo(response); 
} 

Nota que aparece tanto en la clase y en la MockitoAnswers enumeración, por lo que también es compatible con @Mock(answer = RETURNS_SELF) sintaxis.

Cuestiones relacionadas