2017-08-04 231 views
0

此示例代码:的Mockito产生的StackOverflowError当模拟的方法被调用的equals()/ hashCode()方法

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。

+0

可能是由于Mockito使用equals方法本身来验证它是同一个对象。如果您为了减少问题而不重写hash和equals会发生什么? Mockito可能不是这方面最好的用例。 –

回答

2

因为在调用堆栈有org.mockito.internal.invocation.InvocationMatcher#matches这基本上是
invocation.getMock().equals(candidate.getMock())(与invocation.getMock()是你的嘲笑Foo实例),这导致getBar一个呼叫时,嘲笑这将导致调用equals - >getBar - >模拟 - >equals - >getBar - >等...