Betrachten Sie eine Methodensignatur wie:
public String myFunction(String abc);
Kann Mockito dabei helfen, dieselbe Zeichenfolge zurückzugeben, die die Methode empfangen hat?
Betrachten Sie eine Methodensignatur wie:
public String myFunction(String abc);
Kann Mockito dabei helfen, dieselbe Zeichenfolge zurückzugeben, die die Methode empfangen hat?
Antworten:
Sie können eine Antwort in Mockito erstellen. Nehmen wir an, wir haben eine Schnittstelle namens Application mit der Methode myFunction.
public interface Application {
public String myFunction(String abc);
}
Hier ist die Testmethode mit einer Mockito-Antwort:
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"));
}
Seit Mockito 1.9.5 und Java 8 können Sie auch einen Lambda-Ausdruck verwenden:
when(myMock.myFunction(anyString())).thenAnswer(i -> i.getArguments()[0]);
when(...).then(Return.firstParameter())
when(foo(any()).then(i -> i.getArgumentAt(0, Bar.class))
. H. Sie können auch eine Methodenreferenz verwenden und eine echte Methode aufrufen.
Iterator<? extends ClassName>
alle Arten von Cast-Problemen in einer thenReturn()
Anweisung verursacht.
when(foo(any()).thenAnswer(i -> i.getArguments()[0])
Wenn Sie Mockito 1.9.5 oder höher haben, gibt es eine neue statische Methode, mit der Answer
Sie das Objekt für Sie erstellen können . Sie müssen so etwas schreiben
import static org.mockito.Mockito.when;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
when(myMock.myFunction(anyString())).then(returnsFirstArg());
oder alternativ
doAnswer(returnsFirstArg()).when(myMock).myFunction(anyString());
Beachten Sie, dass die returnsFirstArg()
Methode in der AdditionalAnswers
Klasse statisch ist , die für Mockito 1.9.5 neu ist. Sie benötigen also den richtigen statischen Import.
when(...).then(returnsFirstArg())
, ich hatte fälschlicherweise, when(...).thenReturn(returnsFirstArg())
was gabjava.lang.ClassCastException: org.mockito.internal.stubbing.answers.ReturnsArgumentAt cannot be cast to
static org.mockito.AdditionalAnswers.returnsFirstArg
. Dies wird verwendet, um returnFirstArg zu verwenden. Auch kann ich when(myMock.myFunction(any())).then(returnsFirstArg())
in Mockito 2.20 tun . *
Mit Java 8 ist es möglich, auch mit einer älteren Version von Mockito eine einzeilige Antwort zu erstellen:
when(myMock.myFunction(anyString()).then(i -> i.getArgumentAt(0, String.class));
Dies ist natürlich nicht so nützlich wie die AdditionalAnswers
von David Wallace vorgeschlagene, kann aber nützlich sein, wenn Sie das Argument "on the fly" transformieren möchten.
long
, kann dies immer noch mit Boxen und funktionieren Long.class
?
Ich hatte ein sehr ähnliches Problem. Das Ziel war es, einen Dienst zu verspotten, der Objekte beibehält und sie mit ihrem Namen zurückgeben kann. Der Service sieht folgendermaßen aus:
public class RoomService {
public Room findByName(String roomName) {...}
public void persist(Room room) {...}
}
Der Service-Mock verwendet eine Karte zum Speichern der Rauminstanzen.
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;
}
});
Wir können jetzt unsere Tests mit diesem Modell durchführen. Zum Beispiel:
String name = "room";
Room room = new Room(name);
roomService.persist(room);
assertThat(roomService.findByName(name), equalTo(room));
assertNull(roomService.findByName("none"));
Mit Java 8 kann Steves Antwort werden
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: Noch kürzer:
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"));
}
Dies ist eine ziemlich alte Frage, aber ich denke immer noch relevant. Auch die akzeptierte Antwort funktioniert nur für String. Inzwischen gibt es Mockito 2.1 und einige Importe haben sich geändert, daher möchte ich meine aktuelle Antwort teilen:
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());
Die myClass.myFunction würde folgendermaßen aussehen:
public class MyClass {
public ClassOfArgument myFunction(ClassOfArgument argument){
return argument;
}
}
Ich benutze etwas Ähnliches (im Grunde ist es der gleiche Ansatz). Manchmal ist es nützlich, wenn ein Scheinobjekt für bestimmte Eingaben eine vordefinierte Ausgabe zurückgibt. Das geht so:
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
}
}
}
);
Möglicherweise möchten Sie verify () in Kombination mit dem ArgumentCaptor verwenden, um die Ausführung im Test sicherzustellen, und dem ArgumentCaptor, um die Argumente auszuwerten:
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
verify(mock).myFunction(argument.capture());
assertEquals("the expected value here", argument.getValue());
Der Wert des Arguments ist offensichtlich über argument.getValue () für weitere Manipulationen / Überprüfungen / was auch immer zugänglich.
Das ist ein bisschen alt, aber ich bin hierher gekommen, weil ich das gleiche Problem hatte. Ich benutze JUnit aber diesmal in einer Kotlin App mit Mockk. Ich poste hier ein Beispiel als Referenz und Vergleich mit dem Java-Gegenstück:
@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"))
}
Sie können dies mit ArgumentCaptor erreichen
Stellen Sie sich vor, Sie haben eine solche Bohnenfunktion.
public interface Application {
public String myFunction(String abc);
}
Dann in Ihrer Testklasse:
//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.
}
});
ODER wenn Sie Lambda-Fan sind, tun Sie einfach:
//Use ArgumentCaptor to capture the value
ArgumentCaptor<String> param = ArgumentCaptor.forClass(String.class);
when(mock.myFunction(param.capture()))
.thenAnswer((invocation) -> param.getValue());
Zusammenfassung: Verwenden Sie argumentcaptor, um den übergebenen Parameter zu erfassen. Geben Sie später in der Antwort den mit getValue erfassten Wert zurück.
This doesn´t work (anymore?).
Ich bin mir nicht sicher, was du damit meinst. Ich arbeite an meiner Instanz. 2. Entschuldigung, ich bin mir nicht sicher, welchen Punkt Sie anstreben. Die Antwort ist spezifisch für die Frage von OP.