2010-04-21 17 views

Respuesta

697

Puede crear una Respuesta en Mockito. Supongamos que tenemos una interfaz llamada Aplicación con un método myFunction.

public interface Application { 
    public String myFunction(String abc); 
} 

Aquí es el método de ensayo con una respuesta Mockito:

public void testMyFunction() throws Exception { 
    Application mock = mock(Application.class); 
    when(mock.myFunction(anyString())).thenAnswer(new Answer<String>() { 
    @Override 
    public String answer(InvocationOnMock invocation) throws Throwable { 
     Object[] args = invocation.getArguments(); 
     return (String) args[0]; 
    } 
    }); 

    assertEquals("someString",mock.myFunction("someString")); 
    assertEquals("anotherString",mock.myFunction("anotherString")); 
} 

Desde Mockito 1.9.5 y Java 8 hay una manera aún más fácil mediante el uso de las funciones lambda:

when(myMock.myFunction(anyString())).thenAnswer(i -> i.getArguments()[0]);

+0

Esto es lo que estaba buscando, también. ¡Gracias! Mi problema era diferente, sin embargo. Quiero simular un servicio de persistencia (EJB) que almacena objetos y los devuelve por nombre. – migu

+1

Genial, me ahorró mucho tiempo también – Mat

+0

Creo que debería haber una manera más simple usando la captura de argumentos o algo ... – iwein

5

Uso algo similar (básicamente es el mismo enfoque). Algunas veces es útil tener una salida predefinida de retorno de objeto simulada para ciertas entradas. Esto es así:

private Hashtable<InputObject, OutputObject> table = new Hashtable<InputObject, OutputObject>(); 
table.put(input1, ouput1); 
table.put(input2, ouput2); 

... 

when(mockObject.method(any(InputObject.class))).thenAnswer(
     new Answer<OutputObject>() 
     { 
      @Override 
      public OutputObject answer(final InvocationOnMock invocation) throws Throwable 
      { 
       InputObject input = (InputObject) invocation.getArguments()[0]; 
       if (table.containsKey(input)) 
       { 
        return table.get(input); 
       } 
       else 
       { 
        return null; // alternatively, you could throw an exception 
       } 
      } 
     } 
     ); 
33

Tuve un problema muy similar. El objetivo era burlarse de un servicio que persiste en los objetos y puede devolverlos por su nombre. El servicio se ve así:

public class RoomService { 
    public Room findByName(String roomName) {...} 
    public void persist(Room room) {...} 
} 

El simulacro de servicio utiliza un mapa para almacenar las instancias de la habitación.

RoomService roomService = mock(RoomService.class); 
final Map<String, Room> roomMap = new HashMap<String, Room>(); 

// mock for method persist 
doAnswer(new Answer<Void>() { 
    @Override 
    public Void answer(InvocationOnMock invocation) throws Throwable { 
     Object[] arguments = invocation.getArguments(); 
     if (arguments != null && arguments.length > 0 && arguments[0] != null) { 
      Room room = (Room) arguments[0]; 
      roomMap.put(room.getName(), room); 
     } 
     return null; 
    } 
}).when(roomService).persist(any(Room.class)); 

// mock for method findByName 
when(roomService.findByName(anyString())).thenAnswer(new Answer<Room>() { 
    @Override 
    public Room answer(InvocationOnMock invocation) throws Throwable { 
     Object[] arguments = invocation.getArguments(); 
     if (arguments != null && arguments.length > 0 && arguments[0] != null) { 
      String key = (String) arguments[0]; 
      if (roomMap.containsKey(key)) { 
       return roomMap.get(key); 
      } 
     } 
     return null; 
    } 
}); 

Ahora podemos ejecutar nuestras pruebas en este simulacro. Por ejemplo:

String name = "room"; 
Room room = new Room(name); 
roomService.persist(room); 
assertThat(roomService.findByName(name), equalTo(room)); 
assertNull(roomService.findByName("none")); 
391

Si tiene Mockito 1.9.5 o superior, hay un nuevo método estático que puede hacer que el objeto Answer para usted. Usted tiene que escribir algo así como

when(myMock.myFunction(anyString())).then(returnsFirstArg()); 

o alternativamente

doAnswer(returnsFirstArg()).when(myMock).myFunction(anyString()); 

Tenga en cuenta que el método returnsFirstArg() es estático en la clase AdditionalAnswers, que es nuevo para Mockito 1.9.5; por lo que necesitarás la importación estática correcta.

+2

revisando todas las respuestas este 1 es lo mejor ... no sé por qué no es aceptado 1 – Nimrod007

+13

Tal vez porque la respuesta aceptada es anterior a Mockito 1.9.5 – Jay

+7

Nota: es 'cuando (...). luego (returnsFirstArg())', equivocadamente tuve ' when (...). thenReturn (returnsFirstArg()) 'que dio' java.lang.ClassCastException: org.mockito.internal.stubbing.answers.ReturnsArgumentAt no se puede convertir a ' –

36

Con Java 8 es posible crear una respuesta de una línea, incluso con una versión anterior de Mockito:

when(myMock.myFunction(anyString()).then(i -> i.getArgumentAt(0, String.class)); 

Por supuesto, esto no es tan útil como el uso de AdditionalAnswers sugerido por David Wallace, pero podría ser útil si quieres transformar el argumento "sobre la marcha".

+1

Brillante. Gracias. Si el argumento es 'largo', ¿esto todavía puede funcionar con boxeo y' Long.class'? – vikingsteve

24

Con Java 8, Steve's answer puede convertirse en

public void testMyFunction() throws Exception { 
    Application mock = mock(Application.class); 
    when(mock.myFunction(anyString())).thenAnswer(
    invocation -> { 
     Object[] args = invocation.getArguments(); 
     return args[0]; 
    }); 

    assertEquals("someString", mock.myFunction("someString")); 
    assertEquals("anotherString", mock.myFunction("anotherString")); 
} 

EDIT: Aún más corto:

public void testMyFunction() throws Exception { 
    Application mock = mock(Application.class); 
    when(mock.myFunction(anyString())).thenAnswer(
     invocation -> invocation.getArgument(0)); 

    assertEquals("someString", mock.myFunction("someString")); 
    assertEquals("anotherString", mock.myFunction("anotherString")); 
} 
+1

Aún más corto^_^ '' when (mock.myFunction (anyString())). ThenAnswer (invocación -> invocation.getArgument (0)); '' –

+0

Ha fantástico. Editado para reflejar esto ^ – yiwei

1

Es posible que desee utilizar verificar() en combinación con el ArgumentCaptor para asegurar la ejecución de la prueba y el ArgumentCaptor para evaluar los argumentos:

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class); 
verify(mock).myFunction(argument.capture()); 
assertEquals("the expected value here", argument.getValue()); 

El argumento ' El valor de s es obviamente accesible a través del argument.getValue() para una mayor manipulación/verificación/lo que sea.

Cuestiones relacionadas