当在equals()/ hashCode()中调用mocked方法时,Mockito会产生StackOverflowError

时间:2017-08-04 15:19:09

标签: java mockito

此示例代码:

public final class FooBarTest {
    @Test
    public void test() {
        final Foo foo = mock(Foo.class);
        when(foo.getBar()).thenReturn(1);
        new HashSet().add(foo);
    }

    private class Foo {
        @Override
        public final boolean equals(final Object other) {
            return getBar() == 0;
        }

        public int getBar() {
            return 0;
        }

        @Override
        public final int hashCode() {
            return getBar();
        }
    }
}

产生无限循环并抛出异常:

java.lang.StackOverflowError
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:57)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:43)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor$DispatcherDefaultingToRealMethod.interceptSuperCallable(MockMethodInterceptor.java:119)
    at de.weltraumschaf.maconha.FooBarTest$Foo$MockitoMock$217383798.getBar(Unknown Source)
    at de.weltraumschaf.maconha.FooBarTest$Foo.equals(FooBarTest.java:24)
    at org.mockito.internal.invocation.InvocationMatcher.matches(InvocationMatcher.java:81)
    at org.mockito.internal.stubbing.InvocationContainerImpl.findAnswerFor(InvocationContainerImpl.java:82)
    at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:90)
    at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:32)
    at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:36)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:57)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:43)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor$DispatcherDefaultingToRealMethod.interceptSuperCallable(MockMethodInterceptor.java:119)
    at de.weltraumschaf.maconha.FooBarTest$Foo$MockitoMock$217383798.getBar(Unknown Source)
    at de.weltraumschaf.maconha.FooBarTest$Foo.equals(FooBarTest.java:24)
    at org.mockito.internal.invocation.InvocationMatcher.matches(InvocationMatcher.java:81)
    at org.mockito.internal.stubbing.InvocationContainerImpl.findAnswerFor(InvocationContainerImpl.java:82)
    at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:90)
    at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:32)
    at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:36)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:57)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor.doIntercept(MockMethodInterceptor.java:43)
    at org.mockito.internal.creation.bytebuddy.MockMethodInterceptor$DispatcherDefaultingToRealMethod.interceptSuperCallable(MockMethodInterceptor.java:119)
    at de.weltraumschaf.maconha.FooBarTest$Foo$MockitoMock$217383798.getBar(Unknown Source)
    at de.weltraumschaf.maconha.FooBarTest$Foo.equals(FooBarTest.java:24)
    ...

我调试了代码并迷失在Mockito的深处。我唯一能看到的是equals方法被称为正确。我知道Mockito没有存根equals / hashCode / toString。我也很清楚,HashSet调用equals方法来查看其中是否已存在相等的元素。但我无法弄清楚:为什么这种循环无止境?

使用过的Mockito版本是2.8.9和JUnit 4.12。

1 个答案:

答案 0 :(得分:3)

因为在callstack中有org.mockito.internal.invocation.InvocationMatcher#matches基本上是
invocation.getMock().equals(candidate.getMock())invocation.getMock()是您的模拟Foo实例)会导致对getBar的调用被模拟,导致调用equals - > getBar - >模拟 - > equals - > getBar - >等...