diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mocking.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mocking.kt index bf8aa97..d8532a2 100644 --- a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mocking.kt +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mocking.kt @@ -25,7 +25,6 @@ package org.mockito.kotlin -import org.mockito.Incubating import org.mockito.MockSettings import org.mockito.MockedConstruction import org.mockito.MockedStatic @@ -51,7 +50,8 @@ import kotlin.reflect.KClass * @param stubOnly A stub-only mock does not record method invocations, thus saving memory but disallowing verification of invocations. * @param useConstructor Mockito attempts to use constructor when creating instance of the mock. * @param outerInstance Makes it possible to mock non-static inner classes in conjunction with [useConstructor]. - * @param lenient Lenient mocks bypass "strict stubbing" validation. + * @param lenient (DEPRECATED) Lenient mocks bypass "strict stubbing" validation. + * @param strictness Specifies strictness level for the mock. */ inline fun mock( extraInterfaces: Array>? = null, @@ -63,9 +63,10 @@ inline fun mock( verboseLogging: Boolean = false, invocationListeners: Array? = null, stubOnly: Boolean = false, - @Incubating useConstructor: UseConstructor? = null, - @Incubating outerInstance: Any? = null, - @Incubating lenient: Boolean = false + useConstructor: UseConstructor? = null, + outerInstance: Any? = null, + lenient: Boolean = false, + strictness: Strictness? = if (lenient) Strictness.LENIENT else null, ): T { return Mockito.mock( T::class.java, @@ -81,7 +82,7 @@ inline fun mock( stubOnly = stubOnly, useConstructor = useConstructor, outerInstance = outerInstance, - lenient = lenient + strictness = strictness ) )!! } @@ -100,7 +101,8 @@ inline fun mock( * @param stubOnly A stub-only mock does not record method invocations, thus saving memory but disallowing verification of invocations. * @param useConstructor Mockito attempts to use constructor when creating instance of the mock. * @param outerInstance Makes it possible to mock non-static inner classes in conjunction with [useConstructor]. - * @param lenient Lenient mocks bypass "strict stubbing" validation. + * @param lenient (DEPRECATED) Lenient mocks bypass "strict stubbing" validation. + * @param strictness Specifies strictness level for the mock. */ inline fun mock( extraInterfaces: Array>? = null, @@ -112,9 +114,10 @@ inline fun mock( verboseLogging: Boolean = false, invocationListeners: Array? = null, stubOnly: Boolean = false, - @Incubating useConstructor: UseConstructor? = null, - @Incubating outerInstance: Any? = null, - @Incubating lenient: Boolean = false, + useConstructor: UseConstructor? = null, + outerInstance: Any? = null, + lenient: Boolean = false, + strictness: Strictness? = if (lenient) Strictness.LENIENT else null, stubbing: KStubbing.(T) -> Unit ): T { return Mockito.mock( @@ -131,7 +134,7 @@ inline fun mock( stubOnly = stubOnly, useConstructor = useConstructor, outerInstance = outerInstance, - lenient = lenient + strictness = strictness, ) ).apply { KStubbing(this).stubbing(this) }!! } @@ -151,7 +154,8 @@ inline fun mock( * @param stubOnly A stub-only mock does not record method invocations, thus saving memory but disallowing verification of invocations. * @param useConstructor Mockito attempts to use constructor when creating instance of the mock. * @param outerInstance Makes it possible to mock non-static inner classes in conjunction with [useConstructor]. - * @param lenient Lenient mocks bypass "strict stubbing" validation. + * @param lenient (DEPRECATED) Lenient mocks bypass "strict stubbing" validation. + * @param strictness Specifies strictness level for the mock. */ fun withSettings( extraInterfaces: Array>? = null, @@ -163,9 +167,10 @@ fun withSettings( verboseLogging: Boolean = false, invocationListeners: Array? = null, stubOnly: Boolean = false, - @Incubating useConstructor: UseConstructor? = null, - @Incubating outerInstance: Any? = null, - @Incubating lenient: Boolean = false + useConstructor: UseConstructor? = null, + outerInstance: Any? = null, + lenient: Boolean = false, + strictness: Strictness? = if (lenient) Strictness.LENIENT else null, ): MockSettings = Mockito.withSettings().apply { extraInterfaces?.let { extraInterfaces(*it.map { it.java }.toTypedArray()) } name?.let { name(it) } @@ -178,16 +183,19 @@ fun withSettings( if (stubOnly) stubOnly() useConstructor?.let { useConstructor(*it.args) } outerInstance?.let { outerInstance(it) } - if (lenient) strictness(Strictness.LENIENT) + strictness?.let { strictness(it) } } /** * Creates a thread-local mock for static methods on [T]. * + * @param defaultAnswer the default answer when invoking static methods. * @see Mockito.mockStatic */ -inline fun mockStatic(): MockedStatic { - return Mockito.mockStatic(T::class.java) +inline fun mockStatic( + defaultAnswer: Answer? = null, +): MockedStatic { + return Mockito.mockStatic(T::class.java, withSettings(defaultAnswer = defaultAnswer)) } /** diff --git a/tests/src/test/kotlin/test/MockingTest.kt b/tests/src/test/kotlin/test/MockingTest.kt index bd75130..08c6166 100644 --- a/tests/src/test/kotlin/test/MockingTest.kt +++ b/tests/src/test/kotlin/test/MockingTest.kt @@ -13,6 +13,7 @@ import org.mockito.kotlin.whenever import org.mockito.kotlin.any import org.junit.Test import org.mockito.Mockito +import org.mockito.MockitoSession import org.mockito.exceptions.verification.WantedButNotInvoked import org.mockito.invocation.DescribedInvocation import org.mockito.kotlin.argumentCaptor @@ -20,6 +21,7 @@ import org.mockito.kotlin.mockConstruction import org.mockito.kotlin.mockStatic import org.mockito.listeners.InvocationListener import org.mockito.mock.SerializableMode.BASIC +import org.mockito.quality.Strictness import java.io.PrintStream import java.io.Serializable import java.util.* @@ -242,6 +244,49 @@ class MockingTest : TestBase() { expect(result).toNotBeNull() } + @Test + fun mock_strictness_default() { + /* Given */ + val session = Mockito.mockitoSession().strictness(Strictness.STRICT_STUBS).startMocking() + + /* When */ + val result = mock() + whenever(result.intResult()).thenReturn(42) + + /* Then */ + expectErrorWithMessage("Unnecessary stubbings detected") on { + session.finishMocking() + } + } + + @Test + fun mock_withSettingsAPI_lenient() { + /* Given */ + val session = Mockito.mockitoSession().strictness(Strictness.STRICT_STUBS).startMocking() + + /* When */ + val result = mock(lenient = true) + whenever(result.intResult()).thenReturn(42) + + /* Then */ + // Verify no "Unnecessary stubbings detected" exception + session.finishMocking() + } + + @Test + fun mock_withSettingsAPI_strictness_lenient() { + /* Given */ + val session = Mockito.mockitoSession().strictness(Strictness.STRICT_STUBS).startMocking() + + /* When */ + val result = mock(strictness = Strictness.LENIENT) + whenever(result.intResult()).thenReturn(42) + + /* Then */ + // Verify no "Unnecessary stubbings detected" exception + session.finishMocking() + } + @Test fun mockStubbing_withSettingsAPI_extraInterfaces() { /* Given */ @@ -399,6 +444,13 @@ class MockingTest : TestBase() { } } + @Test + fun mockStatic_defaultAnswer_stubbing() { + mockStatic(defaultAnswer = Mockito.CALLS_REAL_METHODS).use { + expect(SomeObject.aStaticMethodReturningString()).toBe("Some Value") + } + } + @Test fun mockConstruction_basic() { mockConstruction().use { mockedConstruction ->