Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix verifyNoMoreInteractions inOrder invocations for spies #2395

Merged
merged 1 commit into from Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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() {}
}
}