如何将Mockito捕获的aguments传递给注入的模拟对象的方法?
我正在尝试测试一个服务类,它在内部使用Spring AMQP连接对象。 此连接对象由Spring注入。 但是,我不希望我的unit testing实际上与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. } }
本代码示例中的注释有望清楚地列出问题。 当Mockito将一个模拟依赖项注入一个真正的类,并且对真实类的unit testing导致它调用mock时,你怎么能在以后检索传递给注入模拟的确切参数?
使用一个或多个ArgumentCaptor
。
目前还不清楚你的类型是什么,但无论如何。 假设你有一个模拟器,它有一个方法doSomething()
以Foo
作为参数,然后你这样做:
final ArgumentCaptor captor = ArgumentCaptor.forClass(Foo.class); verify(mock).doSomething(captor.capture()); final Foo argument = captor.getValue(); // Test the argument
此外,看起来您的方法返回void并且您不希望它执行任何操作。 写下这个:
doNothing().when(theMock).doSomething(any());
您可以将doAnswer()
挂接到doAnswer()
上的send()
方法的amqpTemplateMock
,然后捕获AmqpTemplate.send()
的调用参数。
让testDoSomething()
的第一行成为这样
Mockito.doAnswer(new Answer() { @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());
把它们放在一起,测试就变成了
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() { @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())); } }
这给出了输出
UUID = 8e276a73-12fa-4a7e-a7cc-488d1ce0291f
我通过阅读这篇文章找到了这个, 如何使用mockito使模拟无效方法