Skip to content

Commit 30c50fa

Browse files
authored
Merge pull request #1789 from mockito/sf
Fixed JUnit Jupiter parallel issue
2 parents 214d465 + 5ed8a07 commit 30c50fa

File tree

5 files changed

+138
-20
lines changed

5 files changed

+138
-20
lines changed

settings.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ include("deprecatedPluginsTest",
88
"junitJupiterExtensionTest",
99
"module-test",
1010
"memory-test",
11-
"errorprone")
11+
"errorprone",
12+
"junitJupiterParallelTest")
1213

1314
rootProject.name = "mockito"
1415

subprojects/junit-jupiter/src/main/java/org/mockito/junit/jupiter/MockitoExtension.java

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,30 @@
55
package org.mockito.junit.jupiter;
66

77

8-
import org.junit.jupiter.api.extension.*;
8+
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.create;
9+
import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation;
10+
11+
import java.lang.reflect.Parameter;
12+
import java.util.LinkedHashSet;
13+
import java.util.Optional;
14+
import java.util.Set;
15+
import org.junit.jupiter.api.extension.AfterEachCallback;
16+
import org.junit.jupiter.api.extension.BeforeEachCallback;
17+
import org.junit.jupiter.api.extension.ExtensionContext;
918
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
19+
import org.junit.jupiter.api.extension.ParameterContext;
20+
import org.junit.jupiter.api.extension.ParameterResolutionException;
21+
import org.junit.jupiter.api.extension.ParameterResolver;
22+
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
1023
import org.mockito.Mock;
1124
import org.mockito.Mockito;
1225
import org.mockito.MockitoSession;
26+
import org.mockito.internal.configuration.MockAnnotationProcessor;
1327
import org.mockito.internal.configuration.plugins.Plugins;
1428
import org.mockito.internal.session.MockitoSessionLoggerAdapter;
15-
import org.mockito.internal.configuration.MockAnnotationProcessor;
1629
import org.mockito.junit.MockitoJUnitRunner;
1730
import org.mockito.quality.Strictness;
1831

19-
import java.lang.reflect.Parameter;
20-
import java.util.LinkedHashSet;
21-
import java.util.Optional;
22-
import java.util.Set;
23-
24-
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.create;
25-
import static org.junit.platform.commons.support.AnnotationSupport.findAnnotation;
26-
2732
/**
2833
* Extension that initializes mocks and handles strict stubbings. This extension is the JUnit Jupiter equivalent
2934
* of our JUnit4 {@link MockitoJUnitRunner}.
@@ -188,19 +193,30 @@ private Optional<MockitoSettings> retrieveAnnotationFromTestClasses(final Extens
188193
}
189194

190195
private void collectParentTestInstances(ExtensionContext context, Set<Object> testInstances) {
191-
Optional<ExtensionContext> parent = context.getParent();
196+
Optional<ExtensionContext> initialParent = context.getParent();
192197

193-
while (parent.isPresent() && parent.get() != context.getRoot()) {
194-
ExtensionContext parentContext = parent.get();
198+
// Ignoring first parent avoids parallel execution issues
199+
// We can ignore the first parent because it has the test instance that is already in 'testInstances'
200+
// See how 'testInstances' is populated
201+
initialParent.ifPresent(parent -> collectParentTestInstance(parent.getParent(), context, testInstances));
202+
}
195203

196-
Object testInstance = parentContext.getStore(MOCKITO).remove(TEST_INSTANCE);
204+
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
205+
private void collectParentTestInstance(
206+
Optional<ExtensionContext> parent, ExtensionContext context,
207+
Set<Object> testInstances) {
197208

198-
if (testInstance != null) {
199-
testInstances.add(testInstance);
200-
}
209+
parent.ifPresent(currentParent -> {
210+
if (currentParent != context.getRoot()) {
211+
Object testInstance = currentParent.getStore(MOCKITO).remove(TEST_INSTANCE);
201212

202-
parent = parentContext.getParent();
203-
}
213+
if (testInstance != null) {
214+
testInstances.add(testInstance);
215+
}
216+
217+
collectParentTestInstance(currentParent.getParent(), context, testInstances);
218+
}
219+
});
204220
}
205221

206222
/**
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
description = "Tests that require fine tuned parallel settings for JUnit Jupiter (bug #1630)"
2+
3+
apply from: "$rootDir/gradle/dependencies.gradle"
4+
5+
apply plugin: "java"
6+
7+
dependencies {
8+
testImplementation libraries.junitJupiterApi
9+
testImplementation project(":junit-jupiter")
10+
testRuntime libraries.junitJupiterEngine
11+
}
12+
13+
test {
14+
useJUnitPlatform()
15+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2019 Mockito contributors
3+
* This program is made available under the terms of the MIT License.
4+
*/
5+
package org.mockito;
6+
7+
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.api.extension.ExtendWith;
9+
import org.mockito.junit.jupiter.MockitoExtension;
10+
11+
/**
12+
* See bug #1630
13+
*/
14+
@ExtendWith(MockitoExtension.class)
15+
class ParallelBugTest {
16+
17+
@Mock
18+
private SomeService someService;
19+
20+
@InjectMocks
21+
private AnotherService anotherService;
22+
23+
@Test
24+
void test() {
25+
perform();
26+
}
27+
28+
private void perform() {
29+
// when
30+
anotherService.callSomeService();
31+
32+
// then
33+
Mockito.verify(someService).doSomething();
34+
}
35+
36+
@Test
37+
void test2() {
38+
perform();
39+
}
40+
41+
@Test
42+
void test3() {
43+
perform();
44+
}
45+
46+
@Test
47+
void test4() {
48+
perform();
49+
}
50+
51+
@Test
52+
void test5() {
53+
perform();
54+
}
55+
56+
@Test
57+
void test6() {
58+
perform();
59+
}
60+
61+
@Test
62+
void test7() {
63+
perform();
64+
}
65+
66+
public static class AnotherService {
67+
private final SomeService someService;
68+
69+
public AnotherService(final SomeService someService) {
70+
this.someService = someService;
71+
}
72+
73+
void callSomeService() {
74+
someService.doSomething();
75+
}
76+
}
77+
78+
static class SomeService {
79+
80+
void doSomething() {
81+
}
82+
}
83+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
junit.jupiter.execution.parallel.enabled=true
2+
junit.jupiter.execution.parallel.config.strategy=dynamic
3+
junit.jupiter.execution.parallel.mode.default=concurrent

0 commit comments

Comments
 (0)