如何将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-a​​7cc-488d1ce0291f

我通过阅读这篇文章找到了这个, 如何使用mockito使模拟无效方法