Skip to content

Commit

Permalink
Fixes mockito#2389 : Get existing answer with thread-safe method.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikaël Francoeur committed Oct 12, 2021
1 parent e8f26b3 commit fc5e0b2
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
Expand Up @@ -163,13 +163,20 @@ public Object invokedMock() {
return invocationForStubbing.getInvocation().getMock();
}

public MatchableInvocation getInvocationForStubbing() {
return invocationForStubbing;
}

private RegisteredInvocations createRegisteredInvocations(MockCreationSettings mockSettings) {
return mockSettings.isStubOnly()
? new SingleRegisteredInvocation()
: new DefaultRegisteredInvocations();
}

public Answer findStubbedAnswer() {
synchronized (stubbed) {
for (StubbedInvocationMatcher s : stubbed) {
if (invocationForStubbing.matches(s.getInvocation())) {
return s;
}
}
}
return null;
}
}
Expand Up @@ -20,7 +20,6 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.mock.MockCreationSettings;
import org.mockito.stubbing.Answer;
import org.mockito.stubbing.Stubbing;

/**
* Returning deep stub implementation.
Expand Down Expand Up @@ -80,12 +79,9 @@ private Object deepStub(
throws Throwable {
InvocationContainerImpl container = MockUtil.getInvocationContainer(invocation.getMock());

// matches invocation for verification
// TODO why don't we do container.findAnswer here?
for (Stubbing stubbing : container.getStubbingsDescending()) {
if (container.getInvocationForStubbing().matches(stubbing.getInvocation())) {
return stubbing.answer(invocation);
}
Answer existingAnswer = container.findStubbedAnswer();
if (existingAnswer != null) {
return existingAnswer.answer(invocation);
}

// record deep stub answer
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.mockito.internal.stubbing.defaultanswers;

import static org.mockito.Mockito.mock;

import java.util.List;
import java.util.stream.IntStream;

import org.junit.Test;
import org.mockito.Answers;

public class ReturnsDeepStubsConcurrentTest {

@Test
public void
given_mock_with_returns_deep_stubs__when_called_concurrently__then_does_not_throw_concurrent_modification_exception() {
for (int i = 0; i < 1000; i++) {
Service mock = mock(Service.class, Answers.RETURNS_DEEP_STUBS);
IntStream.range(1, 100).parallel().forEach(index -> mock.doSomething());
}
}

interface Service {
List<String> doSomething();
}
}

0 comments on commit fc5e0b2

Please sign in to comment.