Considérez une signature de méthode comme:
public String myFunction(String abc);
Mockito peut-il aider à renvoyer la même chaîne que la méthode reçue?
Considérez une signature de méthode comme:
public String myFunction(String abc);
Mockito peut-il aider à renvoyer la même chaîne que la méthode reçue?
Réponses:
Vous pouvez créer une réponse dans Mockito. Supposons que nous avons une interface nommée Application avec une méthode myFunction.
public interface Application {
public String myFunction(String abc);
}
Voici la méthode de test avec une réponse 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"));
}
Depuis Mockito 1.9.5 et Java 8, vous pouvez également utiliser une expression lambda:
when(myMock.myFunction(anyString())).thenAnswer(i -> i.getArguments()[0]);
when(...).then(Return.firstParameter())
when(foo(any()).then(i -> i.getArgumentAt(0, Bar.class))
. Et vous pouvez tout aussi bien utiliser une référence de méthode et appeler une méthode réelle.
Iterator<? extends ClassName>
qui provoque toutes sortes de problèmes de transtypage dans une thenReturn()
instruction.
when(foo(any()).thenAnswer(i -> i.getArguments()[0])
Si vous avez Mockito 1.9.5 ou supérieur, il existe une nouvelle méthode statique qui peut créer l' Answer
objet pour vous. Vous devez écrire quelque chose comme
import static org.mockito.Mockito.when;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
when(myMock.myFunction(anyString())).then(returnsFirstArg());
Ou bien
doAnswer(returnsFirstArg()).when(myMock).myFunction(anyString());
Notez que la returnsFirstArg()
méthode est statique dans la AdditionalAnswers
classe, ce qui est nouveau pour Mockito 1.9.5; vous aurez donc besoin de la bonne importation statique.
when(...).then(returnsFirstArg())
, j'ai eu par erreur when(...).thenReturn(returnsFirstArg())
qui a donnéjava.lang.ClassCastException: org.mockito.internal.stubbing.answers.ReturnsArgumentAt cannot be cast to
static org.mockito.AdditionalAnswers.returnsFirstArg
. ceci pour utiliser ReturnsFirstArg. Aussi, je peux le faire when(myMock.myFunction(any())).then(returnsFirstArg())
dans Mockito 2.20. *
Avec Java 8, il est possible de créer une réponse sur une seule ligne, même avec une ancienne version de Mockito:
when(myMock.myFunction(anyString()).then(i -> i.getArgumentAt(0, String.class));
Bien sûr, cela n'est pas aussi utile que l'utilisation AdditionalAnswers
suggérée par David Wallace, mais peut être utile si vous souhaitez transformer l'argument "à la volée".
long
, cela peut-il encore fonctionner avec la boxe et Long.class
?
J'ai eu un problème très similaire. L'objectif était de se moquer d'un service qui persiste sur les objets et peut les renvoyer par leur nom. Le service ressemble à ceci:
public class RoomService {
public Room findByName(String roomName) {...}
public void persist(Room room) {...}
}
La maquette de service utilise une carte pour stocker les instances de salle.
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;
}
});
Nous pouvons maintenant exécuter nos tests sur cette maquette. Par exemple:
String name = "room";
Room room = new Room(name);
roomService.persist(room);
assertThat(roomService.findByName(name), equalTo(room));
assertNull(roomService.findByName("none"));
Avec Java 8, la réponse de Steve peut devenir
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: Encore plus court:
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"));
}
C'est une question assez ancienne mais je pense qu'elle est toujours d'actualité. De plus, la réponse acceptée ne fonctionne que pour String. En attendant, il y a Mockito 2.1 et certaines importations ont changé, je voudrais donc partager ma réponse actuelle:
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());
La fonction myClass.myFunction ressemblerait à:
public class MyClass {
public ClassOfArgument myFunction(ClassOfArgument argument){
return argument;
}
}
J'utilise quelque chose de similaire (en gros c'est la même approche). Parfois, il est utile qu'un objet simulé renvoie une sortie prédéfinie pour certaines entrées. Cela se passe comme ceci:
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
}
}
}
);
Vous souhaiterez peut-être utiliser verify () en combinaison avec ArgumentCaptor pour assurer l'exécution dans le test et ArgumentCaptor pour évaluer les arguments:
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
verify(mock).myFunction(argument.capture());
assertEquals("the expected value here", argument.getValue());
La valeur de l'argument est évidemment accessible via l'argument.getValue () pour une manipulation / vérification / autre.
C'est un peu vieux, mais je suis venu ici parce que j'avais le même problème. J'utilise JUnit mais cette fois dans une application Kotlin avec mockk. Je poste un échantillon ici pour référence et comparaison avec l'homologue 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"))
}
Vous pouvez y parvenir en utilisant ArgumentCaptor
Imaginez que vous ayez une fonction de bean comme ça.
public interface Application {
public String myFunction(String abc);
}
Ensuite, dans votre classe de test:
//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 si vous êtes fan de lambda, faites simplement:
//Use ArgumentCaptor to capture the value
ArgumentCaptor<String> param = ArgumentCaptor.forClass(String.class);
when(mock.myFunction(param.capture()))
.thenAnswer((invocation) -> param.getValue());
Résumé: utilisez argumentcaptor pour capturer le paramètre transmis. Plus tard dans la réponse, renvoyez la valeur capturée à l'aide de getValue.
This doesn´t work (anymore?).
je travaille sur mon instance. 2. Désolé, je ne suis pas clair sur le point que vous essayez de faire valoir. La réponse est spécifique à la question d'OP.