How can I make a method return an argument that was passed to it?
考虑方法签名,例如:
Mockito帮助是否可以返回与方法接收到的字符串相同的字符串?
你可以用mockito创建一个答案。假设我们有一个名为application的接口,它带有一个方法myfunction。
下面是mockito答案的测试方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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")); } |
由于Mockito 1.95和Java 8,使用lambda函数有更简单的方法:
如果您有mockito 1.9.5或更高版本,那么有一个新的静态方法可以使
1 2 3 4 | import static org.mockito.Mockito.when; import static org.mockito.AdditionalAnswers.returnsFirstArg; when(myMock.myFunction(anyString())).then(returnsFirstArg()); |
或者
1 | doAnswer(returnsFirstArg()).when(myMock).myFunction(anyString()); |
注意,
使用Java 8,甚至可以用旧版本的Mockito创建单行答案:
1 |
当然,这并不像大卫华莱士建议的使用
我也遇到了类似的问题。其目标是模拟一个服务,该服务可以持久化对象并按其名称返回它们。服务如下:
1 2 3 4 | public class RoomService { public Room findByName(String roomName) {...} public void persist(Room room) {...} } |
服务模拟使用地图来存储房间实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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; } }); |
我们现在可以在这个模型上运行测试了。例如:
1 2 3 4 5 | String name ="room"; Room room = new Room(name); roomService.persist(room); assertThat(roomService.findByName(name), equalTo(room)); assertNull(roomService.findByName("none")); |
用Java 8,史提夫的答案可以变成
1 2 3 4 5 6 7 8 9 10 11 | 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")); } |
编辑:更短:
1 2 3 4 5 6 7 8 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 } } } ); |
这是一个相当古老的问题,但我认为仍然相关。而且,接受的答案只适用于字符串。同时还有mockito 2.1和一些进口产品发生了变化,所以我想分享我目前的答案:
1 2 3 4 5 6 7 8 9 10 11 | 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()); |
myClass.myFunction如下所示:
1 2 3 4 5 | public class MyClass { public ClassOfArgument myFunction(ClassOfArgument argument){ return argument; } } |
您可能希望将verify()与argumentCaptor结合使用,以确保在测试和argumentCaptor中执行以评估参数:
1 2 3 | ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class); verify(mock).myFunction(argument.capture()); assertEquals("the expected value here", argument.getValue()); |
显然,可以通过argument.getValue()访问参数的值,以便进一步操作/检查/执行任何操作。