Bri*_*128 9 java polymorphism mockito
以下代码显示了我的问题.实际上,我正在尝试使用Mockito的ArgumentCaptor来验证方法是否使用某个具体类调用一次.如果可能的话,我想在这里使用ArgumentCaptor,但我开始怀疑我需要使用自定义的ArgumentMatcher.
问题是该行Mockito.verify(mocked).receive(captor.capture());(编辑:将此添加到下面的代码中)失败,带有TooManyActualInvocations异常(2而不是1).我想了解为什么会发生这种情况 - Mockito的执行效果不佳还是由于泛型的类型擦除造成的限制?
public class FooReceiver {
public void receive(Foo foo) {
}
}
public interface Foo {
}
public class A implements Foo {
}
public class B implements Foo {
}
public class TestedClass {
private FooReceiver receiver;
public TestedClass(FooReceiver receiver) {
this.receiver = receiver;
}
public void doStuff() {
receiver.receive(new A());
receiver.receive(new B());
}
}
public class MyTest {
@Test
public void testingStuff() {
// Setup
FooReceiver mocked = Mockito.mock(FooReceiver.class);
TestedClass t = new TestedClass(mocked);
// Method under test
t.doStuff();
// Verify
ArgumentCaptor<B> captor = ArgumentCaptor.forClass(B.class);
Mockito.verify(mocked).receive(captor.capture()); // Fails here
Assert.assertTrue("What happened?", captor.getValue() instanceof B);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:对于任何有兴趣的人,我最终这样做:
// Verify
final B[] b = new B[1];
ArgumentMatcher<B> filter = new ArgumentMatcher<B>() {
@Override
public boolean matches(Object argument) {
if(argument instanceof B) {
b[0] = (B) argument;
return true;
}
return false;
}
}
Mockito.verify(mocked).receive(Mockito.argThat(filter));
Run Code Online (Sandbox Code Playgroud)
您还可以使用Mockito.isA来验证参数是否属于特定类:
verify(mock).init(isA(ExpectedClass.class));
Run Code Online (Sandbox Code Playgroud)
据我所知,这是一个限制/糟糕的实现。看的时候org.mockito.internal.matchers.CapturingMatcher有
public boolean matches(Object argument) {
return true;
}
Run Code Online (Sandbox Code Playgroud)
这意味着它匹配每个参数/类。
这导致org.mockito.internal.matchers.CapturingMatcher#getAllValues返回 aList<B>但实际上包含 1A和 1B导致在ClassCastException运行期间尝试将它们作为B.
List<Object> arguments; // the invocations
// adds a new invocation
public void captureFrom(Object argument) {
// ...
this.arguments.add(argument);
// ...
}
// return the list of arguments, using raw types remove any compiler checks for validity,
// the returned List contains elements that are not of type T
public List<T> getAllValues() {
// ...
return new ArrayList<T>((List) arguments);
// ...
}
Run Code Online (Sandbox Code Playgroud)
这应该可以通过org.mockito.ArgumentCaptor以将其传递Class<? extends T> clazz到 的方式进行更改CapturingMatcher并因此正确传递类型信息来解决,从而实现正确的matches实现并消除对强制转换/原始类型使用的需要。