Skip to content

Commit

Permalink
Fix verifyNoMoreInteractions inOrder invocations for spies
Browse files Browse the repository at this point in the history
Fixes #2394
  • Loading branch information
TimvdLippe committed Aug 20, 2021
1 parent a53c3d4 commit 8f18142
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 3 deletions.
20 changes: 17 additions & 3 deletions src/main/java/org/mockito/internal/InOrderImpl.java
Expand Up @@ -6,7 +6,7 @@

import static org.mockito.internal.exceptions.Reporter.inOrderRequiresFamiliarMock;

import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;

import org.mockito.InOrder;
Expand All @@ -31,7 +31,7 @@
public class InOrderImpl implements InOrder, InOrderContext {

private final MockitoCore mockitoCore = new MockitoCore();
private final List<Object> mocksToBeVerifiedInOrder = new LinkedList<>();
private final List<Object> mocksToBeVerifiedInOrder = new ArrayList<>();
private final InOrderContext inOrderContext = new InOrderContextImpl();

public List<Object> getMocksToBeVerifiedInOrder() {
Expand All @@ -56,7 +56,7 @@ public <T> T verify(T mock, VerificationMode mode) {
if (!mockingDetails.isMock()) {
throw notAMockPassedToVerify(mock.getClass());
}
if (!mocksToBeVerifiedInOrder.contains(mock)) {
if (!this.objectIsMockToBeVerified(mock)) {
throw inOrderRequiresFamiliarMock();
}
if (mode instanceof VerificationWrapper) {
Expand All @@ -69,6 +69,20 @@ public <T> T verify(T mock, VerificationMode mode) {
return mockitoCore.verify(mock, new InOrderWrapper((VerificationInOrderMode) mode, this));
}

// We can't use `this.mocksToBeVerifiedInOrder.contains`, since that in turn calls `.equals` on
// the mock. Since mocks can be spies and spies get their real equals method calls called, the
// result is that Mockito incorrectly would register an invocation on a mock. This normally
// wouldn't be a problem, unless the user explicitly verifies that no interactions are performed
// on the mock, which would start to fail for the equals invocation.
private boolean objectIsMockToBeVerified(Object mock) {
for (Object inOrderMock : this.mocksToBeVerifiedInOrder) {
if (inOrderMock == mock) {
return true;
}
}
return false;
}

@Override
public boolean isVerified(Invocation i) {
return inOrderContext.isVerified(i);
Expand Down
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2021 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockitousage.spies;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.inOrder;

import org.junit.Test;
import org.mockito.InOrder;

// https://github.com/mockito/mockito/issues/2394
public class SpiesWithRealEqualsAndInOrderTest {

@Test
public void should_be_able_to_handle_in_order_on_spies_with_equals() {
ToBeSpied mock1 = spy(new ToBeSpied());
ToBeSpied mock2 = spy(new ToBeSpied());
mock1.someMethod();
InOrder order = inOrder(mock1, mock2);
order.verify(mock1).someMethod();
order.verifyNoMoreInteractions();
}

static class ToBeSpied {
void someMethod() {}
}
}

0 comments on commit 8f18142

Please sign in to comment.