简体   繁体   English

在ArgumentMatcher之后如何使用ArgumentCaptor?

[英]How do I use ArgumentCaptor after ArgumentMatcher?

I have some common interface to mock: 我有一些通用的接口可以模拟:

public interface RequestHandler {
  public Object handle(Object o);
}

And this mocked interface should handle different requests in single test. 并且该模拟接口应在单个测试中处理不同的请求。

when(mock.handle(isA(ARequest.class))).thenReturn(new AResponse());
when(mock.handle(isA(BRequest.class))).thenReturn(new BResponse());

But I want to capture passed instance of BRequest to check all its params. 但我想捕获传递的BRequest实例以检查其所有参数。 Is it possible somehow? 有可能吗?

For now I see only one solution: build a monstrous extension of ArgumentMatcher . 现在,我仅看到一个解决方案:构建ArgumentMatcher的庞大扩展。 However, I don't like this, because I will not see AssertionError messages. 但是,我不喜欢这样,因为我不会看到AssertionError消息。

Remember: Though matchers are for both stubs and verifications, ArgumentCaptor is for verifications only. 记住:尽管匹配器既用于存根又用于验证,但是ArgumentCaptor仅用于验证。 That makes it simple: 这很简单:

ArgumentCaptor<BRequest> bCaptor = ArgumentCaptor.for(BRequest.class);
when(mock.handle(isA(BRequest.class))).thenReturn(new BResponse());

systemUnderTest.handle(createBRequest());

verify(mock).handle(bCaptor.capture());
BRequest bRequest = bCaptor.getValue();
// your assertions here

Note, however, that that also means you can't use ArgumentCaptor to select the response. 但是请注意,这也意味着您不能使用ArgumentCaptor选择响应。 That's where partial mocks or Answers come in: 那是部分模拟或答案出现的地方:

when(mock.handle(any())).thenAnswer(new Answer<Object>() {
  @Override public Object answer(InvocationOnMock invocation) {
    Object argument = invocation.getArguments()[0];
    // your assertions here, and you can return your desired value
  }
});

Should you choose an ArgumentMatcher, it likely won't be all that monstrous, especially if you skip a factory method and let Mockito's de-camel-casing be your description: 如果您选择一个ArgumentMatcher,它可能不会那么可怕,尤其是如果您跳过工厂方法并让Mockito的脱骆驼壳作为您的描述:

public static class IsAnAppropriateBRequest extends ArgumentMatcher<Object> {
  @Override public boolean matches(Object object) {
    if !(object instanceof BRequest) {
      return false;
    }
    BRequest bRequest = (BRequest) object;
    // your assertions here
  }
}

when(mock.handle(argThat(new IsAnAppropriateBRequest())))
    .thenReturn(new BResponse());

Okay, first of all, the fact that this method can take so many different types of parameters is a code smell. 好的,首先,此方法可以采用许多不同类型的参数的事实是代码的味道。 A method that returns many different kinds of responses for different input parameters is a clear violation of this. 对于不同的输入参数返回许多不同种类的响应的方法明显违反了此方法。 See One Thing: Extract till you Drop. 看到一件事:提取直到跌落。

For years authors and consultants (like me) have been telling us that functions should do one thing. 多年来,作者和顾问(像我一样)一直在告诉我们,功能应该做一件事。 They should do it well. 他们应该做好。 They should do it only. 他们只能这样做。

That said, you can pass a Partial Mock into your class. 也就是说,您可以将部分模拟传递给您的班级。 See: Real Partial Mocks 另请: 真实的局部模拟

Example: 例:

BRequest bSpy = spy(new BRequest());
when(mock.handle(bSpy))).thenReturn(new BResponse());
verify(bSpy, times(2)).someMethod();

bSpy won't return null, because it's a real instance of a BRequest , but because it's a spy, it allows you to call things like verify on it. bSpy不会返回null,因为它是BRequest真实实例 ,但是由于它是间谍,因此它允许您调用诸如verify的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM