Java Mockito 如何捕获传递给注入的模拟对象方法的参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29169759/
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
How can Mockito capture arguments passed to an injected mock object's methods?
提问by Steve Perkins
I am trying to test a service class, which internally makes use of a Spring AMQP connection object. This connection object is injected by Spring. However, I don't want my unit test to actually communicate with the AMQP broker, so I am using Mockito inject a mock of the connection object.
我正在尝试测试一个服务类,它在内部使用 Spring AMQP 连接对象。这个连接对象是由 Spring 注入的。但是,我不希望我的单元测试实际与 AMQP 代理通信,因此我使用 Mockito 注入连接对象的模拟。
/**
* The real service class being tested. Has an injected dependency.
*/
public class UserService {
@Autowired
private AmqpTemplate amqpTemplate;
public final String doSomething(final String inputString) {
final String requestId = UUID.randomUUID().toString();
final Message message = ...;
amqpTemplate.send(requestId, message);
return requestId;
}
}
/**
* Unit test
*/
public class UserServiceTest {
/** This is the class whose real code I want to test */
@InjectMocks
private UserService userService;
/** This is a dependency of the real class, that I wish to override with a mock */
@Mock
private AmqpTemplate amqpTemplateMock;
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testDoSomething() {
doNothing().when(amqpTemplateMock).send(anyString(), any(Message.class));
// Call the real service class method, which internally will make
// use of the mock (I've verified that this works right).
userService.doSomething(...);
// Okay, now I need to verify that UUID string returned by
// "userService.doSomething(...) matches the argument that method
// internally passed to "amqpTemplateMock.send(...)". Up here
// at the unit test level, how can I capture the arguments passed
// to that inject mock for comparison?
//
// Since the value being compared is a UUID string created
// internally within "userService", I cannot just verify against
// a fixed expected value. The UUID will by definition always be
// unique.
}
}
The comments in this code sample hopefully lay out the question clearly. When Mockito injects a mock dependency into a real class, and unit tests on the real class cause it to make calls to the mock, how can you later retrieve the exact arguments that were passed to the injected mock?
希望此代码示例中的注释清楚地说明了问题。当 Mockito 将一个模拟依赖项注入到一个真实的类中,并且对真实类的单元测试导致它调用模拟时,你以后如何检索传递给注入的模拟的确切参数?
采纳答案by fge
Use one, or more, ArgumentCaptor
s.
使用一个或多个ArgumentCaptor
s。
It is unclear what your types are here, but anyway. Let's suppose you have a mock which has a method doSomething()
taking a Foo
as an argument, then you do this:
目前还不清楚你的类型是什么,但无论如何。假设你有一个模拟,它有一个doSomething()
以 aFoo
作为参数的方法,然后你这样做:
final ArgumentCaptor<Foo> captor = ArgumentCaptor.forClass(Foo.class);
verify(mock).doSomething(captor.capture());
final Foo argument = captor.getValue();
// Test the argument
Also, it looks like your method returns void and you don't want it to do anything. Just write this:
此外,看起来您的方法返回 void 并且您不希望它执行任何操作。只写这个:
doNothing().when(theMock).doSomething(any());
回答by Kirby
You can hook doAnswer()
to the stub of the send()
method on amqpTemplateMock
and then capture the invocation arguments of AmqpTemplate.send()
.
您可以挂钩方法doAnswer()
的存根send()
on amqpTemplateMock
,然后捕获 的调用参数AmqpTemplate.send()
。
Make the first line of your testDoSomething()
be this
让你的第一行testDoSomething()
是这个
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(final InvocationOnMock invocation) {
final Object[] args = invocation.getArguments();
System.out.println("UUID=" + args[0]); // do your assertions here
return null;
}
}).when(amqpTemplateMock).send(Matchers.anyString(), Matchers.anyObject());
putting it all together, the test becomes
把它们放在一起,测试变成
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class UserServiceTest {
/** This is the class whose real code I want to test */
@InjectMocks
private UserService userService;
/** This is a dependency of the real class, that I wish to override with a mock */
@Mock
private AmqpTemplate amqpTemplateMock;
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testDoSomething() throws Exception {
Mockito.doAnswer(new Answer<Void>() {
@Override
public Void answer(final InvocationOnMock invocation) {
final Object[] args = invocation.getArguments();
System.out.println("UUID=" + args[0]); // do your assertions here
return null;
}
}).when(amqpTemplateMock).send(Matchers.anyString(), Matchers.anyObject());
userService.doSomething(Long.toString(System.currentTimeMillis()));
}
}
This gives output
这给出了输出
UUID=8e276a73-12fa-4a7e-a7cc-488d1ce0291f
UUID=8e276a73-12fa-4a7e-a7cc-488d1ce0291f
I found this by reading this post, How to make mock to void methods with mockito
我通过阅读这篇文章找到了这一点, How to make mock to void methods with mockito