Skip to content

Commit ff98622

Browse files
Restore behavior for mocks configured without strictness (#2659)
Fixes #2656
1 parent 1fbef57 commit ff98622

File tree

8 files changed

+179
-22
lines changed

8 files changed

+179
-22
lines changed

src/main/java/org/mockito/Mock.java

+30-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import java.lang.annotation.Target;
1414

1515
import org.mockito.junit.MockitoJUnitRunner;
16-
import org.mockito.quality.Strictness;
1716
import org.mockito.stubbing.Answer;
1817

1918
/**
@@ -34,12 +33,13 @@
3433
* @Mock(name = "database") private ArticleDatabase dbMock;
3534
* @Mock(answer = RETURNS_MOCKS) private UserProvider userProvider;
3635
* @Mock(extraInterfaces = {Queue.class, Observer.class}) private ArticleMonitor articleMonitor;
36+
* @Mock(strictness = Mock.Strictness.LENIENT) private ArticleConsumer articleConsumer;
3737
* @Mock(stubOnly = true) private Logger logger;
3838
*
3939
* private ArticleManager manager;
4040
*
4141
* @Before public void setup() {
42-
* manager = new ArticleManager(userProvider, database, calculator, articleMonitor, logger);
42+
* manager = new ArticleManager(userProvider, database, calculator, articleMonitor, articleConsumer, logger);
4343
* }
4444
* }
4545
*
@@ -117,10 +117,35 @@
117117
boolean lenient() default false;
118118

119119
/**
120-
* Mock will have custom strictness, see {@link MockSettings#strictness(Strictness)}.
120+
* Mock will have custom strictness, see {@link MockSettings#strictness(org.mockito.quality.Strictness)}.
121121
* For examples how to use 'Mock' annotation and parameters see {@link Mock}.
122122
*
123-
* @since 4.6.0
123+
* @since 4.6.1
124124
*/
125-
Strictness strictness() default Strictness.STRICT_STUBS;
125+
Strictness strictness() default Strictness.TEST_LEVEL_DEFAULT;
126+
127+
enum Strictness {
128+
129+
/**
130+
* Default value used to indicate the mock does not override the test level strictness.
131+
*
132+
* @since 4.6.1
133+
*/
134+
TEST_LEVEL_DEFAULT,
135+
136+
/**
137+
* See {@link org.mockito.quality.Strictness#LENIENT}
138+
*/
139+
LENIENT,
140+
141+
/**
142+
* See {@link org.mockito.quality.Strictness#WARN}
143+
*/
144+
WARN,
145+
146+
/**
147+
* See {@link org.mockito.quality.Strictness#STRICT_STUBS}
148+
*/
149+
STRICT_STUBS
150+
}
126151
}

src/main/java/org/mockito/internal/configuration/MockAnnotationProcessor.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.mockito.Mockito;
1818
import org.mockito.exceptions.base.MockitoException;
1919
import org.mockito.internal.util.Supplier;
20+
import org.mockito.quality.Strictness;
2021

2122
/**
2223
* Instantiates a mock on a field annotated by {@link Mock}
@@ -28,6 +29,7 @@ public Object process(Mock annotation, Field field) {
2829
annotation, field.getType(), field::getGenericType, field.getName());
2930
}
3031

32+
@SuppressWarnings("deprecation")
3133
public static Object processAnnotationForMock(
3234
Mock annotation, Class<?> type, Supplier<Type> genericType, String name) {
3335
MockSettings mockSettings = Mockito.withSettings();
@@ -45,10 +47,12 @@ public static Object processAnnotationForMock(
4547
if (annotation.stubOnly()) {
4648
mockSettings.stubOnly();
4749
}
48-
mockSettings.strictness(annotation.strictness());
4950
if (annotation.lenient()) {
5051
mockSettings.lenient();
5152
}
53+
if (annotation.strictness() != Mock.Strictness.TEST_LEVEL_DEFAULT) {
54+
mockSettings.strictness(Strictness.valueOf(annotation.strictness().toString()));
55+
}
5256

5357
// see @Mock answer default value
5458
mockSettings.defaultAnswer(annotation.answer());

src/main/java/org/mockito/internal/creation/MockSettingsImpl.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,10 @@ public MockSettings lenient() {
247247

248248
@Override
249249
public MockSettings strictness(Strictness strictness) {
250-
this.strictness = strictness;
251250
if (strictness == null) {
252251
throw strictnessDoesNotAcceptNullParameter();
253252
}
253+
this.strictness = strictness;
254254
return this;
255255
}
256256

src/main/java/org/mockito/internal/creation/settings/CreationSettings.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class CreationSettings<T> implements MockCreationSettings<T>, Serializabl
4545
private boolean useConstructor;
4646
private Object outerClassInstance;
4747
private Object[] constructorArgs;
48-
protected Strictness strictness = Strictness.STRICT_STUBS;
48+
protected Strictness strictness = null;
4949

5050
public CreationSettings() {}
5151

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2022 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.Test;
8+
import org.junit.experimental.runners.Enclosed;
9+
import org.junit.runner.RunWith;
10+
import org.junit.runners.Parameterized;
11+
12+
import static org.hamcrest.Matchers.not;
13+
import static org.junit.Assume.assumeThat;
14+
15+
@RunWith(Enclosed.class)
16+
public class MockTest {
17+
18+
@RunWith(value = Parameterized.class)
19+
public static class StrictnessToMockStrictnessTest {
20+
21+
public org.mockito.quality.Strictness strictness;
22+
23+
public StrictnessToMockStrictnessTest(org.mockito.quality.Strictness strictness) {
24+
this.strictness = strictness;
25+
}
26+
27+
@Test
28+
public void should_have_matching_enum_in_mock_strictness_enum() {
29+
Mock.Strictness.valueOf(strictness.name());
30+
}
31+
32+
@Parameterized.Parameters(name = "{0}")
33+
public static org.mockito.quality.Strictness[] data() {
34+
return org.mockito.quality.Strictness.values();
35+
}
36+
}
37+
38+
@RunWith(value = Parameterized.class)
39+
public static class MockStrictnessToStrictnessTest {
40+
41+
public Mock.Strictness strictness;
42+
43+
public MockStrictnessToStrictnessTest(Mock.Strictness strictness) {
44+
this.strictness = strictness;
45+
}
46+
47+
@Test
48+
public void should_have_matching_enum_in_strictness_enum() {
49+
assumeThat("Ignore NOT_SET", strictness, not(Mock.Strictness.TEST_LEVEL_DEFAULT));
50+
org.mockito.quality.Strictness.valueOf(strictness.name());
51+
}
52+
53+
@Parameterized.Parameters(name = "{0}")
54+
public static Mock.Strictness[] data() {
55+
return Mock.Strictness.values();
56+
}
57+
}
58+
}

src/test/java/org/mockitousage/strictness/StrictnessMockAnnotationTest.java

+44-14
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import org.assertj.core.api.Assertions;
88
import org.junit.Rule;
99
import org.junit.Test;
10+
import org.junit.experimental.runners.Enclosed;
11+
import org.junit.runner.RunWith;
1012
import org.mockito.Mock;
1113
import org.mockito.exceptions.misusing.PotentialStubbingProblem;
1214
import org.mockito.junit.MockitoJUnit;
@@ -16,28 +18,56 @@
1618

1719
import static org.mockito.Mockito.when;
1820

21+
@RunWith(Enclosed.class)
1922
public class StrictnessMockAnnotationTest {
2023

21-
public @Rule MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
24+
public static class StrictStubsTest {
25+
public @Rule MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
2226

23-
@Mock(strictness = Strictness.LENIENT)
24-
IMethods lenientMock;
27+
@Mock(strictness = Mock.Strictness.LENIENT)
28+
IMethods lenientMock;
2529

26-
@Mock IMethods regularMock;
30+
@Mock IMethods regularMock;
2731

28-
@Test
29-
public void mock_is_lenient() {
30-
when(lenientMock.simpleMethod("1")).thenReturn("1");
32+
@Test
33+
public void mock_is_lenient() {
34+
when(lenientMock.simpleMethod("1")).thenReturn("1");
3135

32-
// then lenient mock does not throw:
33-
ProductionCode.simpleMethod(lenientMock, "3");
36+
// then lenient mock does not throw:
37+
ProductionCode.simpleMethod(lenientMock, "3");
38+
}
39+
40+
@Test
41+
public void mock_is_strict() {
42+
when(regularMock.simpleMethod("2")).thenReturn("2");
43+
44+
Assertions.assertThatThrownBy(() -> ProductionCode.simpleMethod(regularMock, "4"))
45+
.isInstanceOf(PotentialStubbingProblem.class);
46+
}
3447
}
3548

36-
@Test
37-
public void mock_is_strict() {
38-
when(regularMock.simpleMethod("2")).thenReturn("2");
49+
public static class LenientStubsTest {
50+
public @Rule MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT);
51+
52+
@Mock IMethods lenientMock;
53+
54+
@Mock(strictness = Mock.Strictness.STRICT_STUBS)
55+
IMethods regularMock;
56+
57+
@Test
58+
public void mock_is_lenient() {
59+
when(lenientMock.simpleMethod("1")).thenReturn("1");
60+
61+
// then lenient mock does not throw:
62+
ProductionCode.simpleMethod(lenientMock, "3");
63+
}
64+
65+
@Test
66+
public void mock_is_strict() {
67+
when(regularMock.simpleMethod("2")).thenReturn("2");
3968

40-
Assertions.assertThatThrownBy(() -> ProductionCode.simpleMethod(regularMock, "4"))
41-
.isInstanceOf(PotentialStubbingProblem.class);
69+
Assertions.assertThatThrownBy(() -> ProductionCode.simpleMethod(regularMock, "4"))
70+
.isInstanceOf(PotentialStubbingProblem.class);
71+
}
4272
}
4373
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
* Copyright (c) 2022 Mockito contributors
3+
* This program is made available under the terms of the MIT License.
4+
*/
5+
package org.mockitousage;
6+
7+
import java.util.function.Predicate;
8+
9+
public class ProductionCode {
10+
11+
@SuppressWarnings("ReturnValueIgnored")
12+
public static void simpleMethod(Predicate<String> mock, String argument) {
13+
mock.test(argument);
14+
}
15+
}

subprojects/junit-jupiter/src/test/java/org/mockitousage/StrictnessTest.java

+25
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
import org.mockito.junit.jupiter.MockitoSettings;
2222
import org.mockito.quality.Strictness;
2323

24+
import java.util.Optional;
2425
import java.util.function.Function;
26+
import java.util.function.Predicate;
2527

2628
import static org.assertj.core.api.Assertions.assertThat;
2729
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
@@ -162,6 +164,29 @@ void inherits_strictness_from_base_class() {
162164
assertThat(result.getStatus()).isEqualTo(TestExecutionResult.Status.SUCCESSFUL);
163165
}
164166

167+
@ExtendWith(MockitoExtension.class)
168+
@MockitoSettings(strictness = Strictness.LENIENT)
169+
static class LenientMockitoSettings {
170+
171+
@Mock
172+
private Predicate<String> rootMock;
173+
174+
@Test
175+
void should_not_throw_on_potential_stubbing_issue() {
176+
Mockito.doReturn(true).when(rootMock).test("Foo");
177+
178+
ProductionCode.simpleMethod(rootMock, "Bar");
179+
}
180+
}
181+
182+
@Test
183+
void use_strictness_from_settings_annotation() {
184+
TestExecutionResult result = invokeTestClassAndRetrieveMethodResult(LenientMockitoSettings.class);
185+
186+
assertThat(result.getThrowable()).isEqualTo(Optional.empty());
187+
assertThat(result.getStatus()).isEqualTo(TestExecutionResult.Status.SUCCESSFUL);
188+
}
189+
165190
private TestExecutionResult invokeTestClassAndRetrieveMethodResult(Class<?> clazz) {
166191
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
167192
.selectors(

0 commit comments

Comments
 (0)