Reputation: 428
This example code:
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();
}
}
}
produces an endless loop and throws an exception:
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)
...
I debugged into the code and got lost in the depth of Mockito. The only thing I can see is that the equals method is called right. I know that Mockito does not stub equals
/hashCode
/toString
. It is also clear to me that the equals
method is called by the HashSet to see if there is already an equal element in it. But what I can't figure out: Why does this loop endless?
The used Mockito version is 2.8.9 and JUnit 4.12.
Upvotes: 0
Views: 4588
Reputation: 57124
Because in the callstack there is org.mockito.internal.invocation.InvocationMatcher#matches
which basically is
invocation.getMock().equals(candidate.getMock())
(with invocation.getMock()
being your mocked Foo
instance) which causes a call to getBar
which is mocked which causes a call to equals
-> getBar
-> mock -> equals
-> getBar
-> etc...
Upvotes: 4