Considere uma assinatura de método como:
public String myFunction(String abc);
O Mockito pode ajudar a retornar a mesma string que o método recebeu?
Considere uma assinatura de método como:
public String myFunction(String abc);
O Mockito pode ajudar a retornar a mesma string que o método recebeu?
Respostas:
Você pode criar uma resposta no Mockito. Vamos supor, temos uma interface chamada Application com o método myFunction.
public interface Application {
public String myFunction(String abc);
}
Aqui está o método de teste com uma resposta do 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 o Mockito 1.9.5 e o Java 8, você também pode usar uma expressão lambda:
when(myMock.myFunction(anyString())).thenAnswer(i -> i.getArguments()[0]);
when(...).then(Return.firstParameter())
when(foo(any()).then(i -> i.getArgumentAt(0, Bar.class))
. E você também pode usar uma referência de método e chamar método real.
Iterator<? extends ClassName>
que causa todos os tipos de problemas de conversão em uma thenReturn()
instrução.
when(foo(any()).thenAnswer(i -> i.getArguments()[0])
Se você possui o Mockito 1.9.5 ou superior, existe um novo método estático que pode criar o Answer
objeto para você. Você precisa escrever algo como
import static org.mockito.Mockito.when;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
when(myMock.myFunction(anyString())).then(returnsFirstArg());
ou alternativamente
doAnswer(returnsFirstArg()).when(myMock).myFunction(anyString());
Observe que o returnsFirstArg()
método é estático na AdditionalAnswers
classe, que é nova no Mockito 1.9.5; então você precisará da importação estática correta.
when(...).then(returnsFirstArg())
, eu equivocadamente tinha when(...).thenReturn(returnsFirstArg())
que deujava.lang.ClassCastException: org.mockito.internal.stubbing.answers.ReturnsArgumentAt cannot be cast to
static org.mockito.AdditionalAnswers.returnsFirstArg
. isso para usar ReturnsFirstArg. Além disso, eu posso fazer when(myMock.myFunction(any())).then(returnsFirstArg())
no Mockito 2.20. *
Com o Java 8, é possível criar uma resposta de uma linha mesmo com a versão mais antiga do Mockito:
when(myMock.myFunction(anyString()).then(i -> i.getArgumentAt(0, String.class));
Claro que isso não é tão útil quanto o uso AdditionalAnswers
sugerido por David Wallace, mas pode ser útil se você quiser transformar o argumento "on the fly".
long
, isso ainda pode funcionar com boxe e Long.class
?
Eu tive um problema muito parecido. O objetivo era zombar de um serviço que persiste em Objetos e pode devolvê-los pelo nome. O serviço fica assim:
public class RoomService {
public Room findByName(String roomName) {...}
public void persist(Room room) {...}
}
A simulação de serviço usa um mapa para armazenar as instâncias da sala.
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;
}
});
Agora podemos executar nossos testes com essa simulação. Por exemplo:
String name = "room";
Room room = new Room(name);
roomService.persist(room);
assertThat(roomService.findByName(name), equalTo(room));
assertNull(roomService.findByName("none"));
Com o Java 8, a resposta de Steve pode se tornar
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: Ainda mais curto:
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"));
}
Esta é uma pergunta bastante antiga, mas acho que ainda é relevante. Além disso, a resposta aceita funciona apenas para String. Enquanto isso, há o Mockito 2.1 e algumas importações foram alteradas, então eu gostaria de compartilhar minha resposta atual:
import static org.mockito.AdditionalAnswers.returnsFirstArg;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@Mock
private MyClass myClass;
// this will return anything you pass, but it's pretty unrealistic
when(myClass.myFunction(any())).then(returnsFirstArg());
// it is more "life-like" to accept only the right type
when(myClass.myFunction(any(ClassOfArgument.class))).then(returnsFirstArg());
O myClass.myFunction seria semelhante a:
public class MyClass {
public ClassOfArgument myFunction(ClassOfArgument argument){
return argument;
}
}
Eu uso algo semelhante (basicamente é a mesma abordagem). Às vezes, é útil fazer com que um objeto simulado retorne uma saída predefinida para determinadas entradas. É assim:
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
}
}
}
);
Convém usar o Checker () em combinação com o ArgumentCaptor para garantir a execução no teste e o ArgumentCaptor para avaliar os argumentos:
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
verify(mock).myFunction(argument.capture());
assertEquals("the expected value here", argument.getValue());
O valor do argumento é obviamente acessível através do argument.getValue () para manipulação / verificação adicional / o que for.
Isso é um pouco antigo, mas eu vim aqui porque tinha o mesmo problema. Estou usando o JUnit, mas desta vez em um aplicativo Kotlin com mockk. Estou postando uma amostra aqui para referência e comparação com a contraparte Java:
@Test
fun demo() {
// mock a sample function
val aMock: (String) -> (String) = mockk()
// make it return the same as the argument on every invocation
every {
aMock.invoke(any())
} answers {
firstArg()
}
// test it
assertEquals("senko", aMock.invoke("senko"))
assertEquals("senko1", aMock.invoke("senko1"))
assertNotEquals("not a senko", aMock.invoke("senko"))
}
Você pode conseguir isso usando ArgumentCaptor
Imagine que você tem a função de bean assim.
public interface Application {
public String myFunction(String abc);
}
Então na sua classe de teste:
//Use ArgumentCaptor to capture the value
ArgumentCaptor<String> param = ArgumentCaptor.forClass(String.class);
when(mock.myFunction(param.capture())).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
return param.getValue();//return the captured value.
}
});
OU se você é um fã de lambda, faça:
//Use ArgumentCaptor to capture the value
ArgumentCaptor<String> param = ArgumentCaptor.forClass(String.class);
when(mock.myFunction(param.capture()))
.thenAnswer((invocation) -> param.getValue());
Resumo: Use o argumentocaptor para capturar o parâmetro passado. Posteriormente, em resposta, retorne o valor capturado usando getValue.
This doesn´t work (anymore?).
isso funcionando na minha instância. 2. Desculpe, não sei ao certo o que você está tentando fazer. A resposta é específica para a pergunta do OP.