Java 使模拟方法返回传递给它的参数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2684630/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Making a mocked method return an argument that was passed to it
提问by Abhijeet Kashnia
Consider a method signature like:
考虑一个方法签名,如:
public String myFunction(String abc);
Can Mockito help return the same string that the method received?
Mockito 可以帮助返回与方法接收到的相同的字符串吗?
采纳答案by Steve
You can create an Answer in Mockito. Let's assume, we have an interface named Application with a method myFunction.
您可以在 Mockito 中创建答案。让我们假设,我们有一个名为 Application 的接口,其中包含一个 myFunction 方法。
public interface Application {
public String myFunction(String abc);
}
Here is the test method with a Mockito answer:
这是带有 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"));
}
Since Mockito 1.9.5 and Java 8, you can also use a lambda expression:
从 Mockito 1.9.5 和 Java 8 开始,您还可以使用 lambda 表达式:
when(myMock.myFunction(anyString())).thenAnswer(i -> i.getArguments()[0]);
回答by martin
I use something similar (basically it's the same approach). Sometimes it's useful to have a mock object return pre-defined output for certain inputs. That goes like this:
我使用类似的东西(基本上是相同的方法)。有时让模拟对象为某些输入返回预定义的输出很有用。事情是这样的:
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
}
}
}
);
回答by migu
I had a very similar problem. The goal was to mock a service that persists Objects and can return them by their name. The service looks like this:
我有一个非常相似的问题。目标是模拟一个服务,该服务可以持久化对象并可以按名称返回它们。该服务如下所示:
public class RoomService {
public Room findByName(String roomName) {...}
public void persist(Room room) {...}
}
The service mock uses a map to store the Room instances.
服务模拟使用地图来存储 Room 实例。
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;
}
});
We can now run our tests on this mock. For example:
我们现在可以在这个模拟上运行我们的测试。例如:
String name = "room";
Room room = new Room(name);
roomService.persist(room);
assertThat(roomService.findByName(name), equalTo(room));
assertNull(roomService.findByName("none"));
回答by Dawood ibn Kareem
If you have Mockito 1.9.5 or higher, there is a new static method that can make the Answer
object for you. You need to write something like
如果你有 Mockito 1.9.5 或更高版本,有一个新的静态方法可以Answer
为你创建对象。你需要写一些类似的东西
import static org.mockito.Mockito.when;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
when(myMock.myFunction(anyString())).then(returnsFirstArg());
or alternatively
或者
doAnswer(returnsFirstArg()).when(myMock).myFunction(anyString());
Note that the returnsFirstArg()
method is static in the AdditionalAnswers
class, which is new to Mockito 1.9.5; so you'll need the right static import.
请注意,该returnsFirstArg()
方法在AdditionalAnswers
类中是静态的,这是 Mockito 1.9.5 的新功能;所以你需要正确的静态导入。
回答by Pawe? Dyda
With Java 8 it is possible to create a one-line answer even with older version of Mockito:
使用 Java 8,即使使用旧版本的 Mockito 也可以创建单行答案:
when(myMock.myFunction(anyString()).then(i -> i.getArgumentAt(0, String.class));
Of course this is not as useful as using AdditionalAnswers
suggested by David Wallace, but might be useful if you want to transform argument "on the fly".
当然,这不像AdditionalAnswers
David Wallace 建议的那样有用,但如果您想“即时”转换参数,可能会很有用。
回答by yiwei
With Java 8, Steve's answercan become
使用 Java 8,史蒂夫的答案可以变成
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: Even shorter:
编辑:更短:
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"));
}
回答by fl0w
You might want to use verify() in combination with the ArgumentCaptor to assure execution in the test and the ArgumentCaptor to evaluate the arguments:
您可能希望将 verify() 与 ArgumentCaptor 结合使用以确保在测试中执行,并使用 ArgumentCaptor 来评估参数:
ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);
verify(mock).myFunction(argument.capture());
assertEquals("the expected value here", argument.getValue());
The argument's value is obviously accessible via the argument.getValue() for further manipulation / checking /whatever.
参数的值显然可以通过 argument.getValue() 访问以进行进一步操作/检查/无论什么。
回答by LazR
This is a pretty old question but i think still relevant. Also the accepted answer works only for String. Meanwhile there is Mockito 2.1 and some imports have changed, so i would like to share my current answer:
这是一个很老的问题,但我认为仍然相关。此外,接受的答案仅适用于字符串。同时有 Mockito 2.1 和一些进口已经改变,所以我想分享我目前的答案:
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());
The myClass.myFunction would look like:
myClass.myFunction 看起来像:
public class MyClass {
public ClassOfArgument myFunction(ClassOfArgument argument){
return argument;
}
}
回答by Lachezar Balev
This is a bit old, but I came here because I had the same issue. I'm using JUnit but this time in a Kotlin app with mockk. I'm posting a sample here for reference and comparison with the Java counterpart:
这有点旧,但我来到这里是因为我遇到了同样的问题。我正在使用 JUnit,但这次是在带有 mockk 的 Kotlin 应用程序中。我在这里发布一个示例以供参考并与 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"))
}
回答by Cyril Cherian
You can achieve this by using ArgumentCaptor
您可以通过使用ArgumentCaptor来实现这一点
Imagine you have bean function like so.
想象一下你有这样的 bean 函数。
public interface Application {
public String myFunction(String abc);
}
Then in your test class:
然后在您的测试类中:
//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.
}
});
ORif you fan of lambda simply do:
或者,如果您喜欢 lambda,只需执行以下操作:
//Use ArgumentCaptor to capture the value
ArgumentCaptor<String> param = ArgumentCaptor.forClass(String.class);
when(mock.myFunction(param.capture()))
.thenAnswer((invocation) -> param.getValue());
Summary:Use argumentcaptor, to capture the parameter passed. Later in answer return the value captured using getValue.
总结:使用argumentcaptor,捕获传入的参数。稍后在回答中返回使用 getValue 捕获的值。