Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mocking.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

package org.mockito.kotlin

import org.mockito.Incubating
import org.mockito.MockSettings
import org.mockito.MockedConstruction
import org.mockito.MockedStatic
Expand All @@ -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 <reified T : Any> mock(
extraInterfaces: Array<out KClass<out Any>>? = null,
Expand All @@ -63,9 +63,10 @@ inline fun <reified T : Any> mock(
verboseLogging: Boolean = false,
invocationListeners: Array<InvocationListener>? = 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,
Expand All @@ -81,7 +82,7 @@ inline fun <reified T : Any> mock(
stubOnly = stubOnly,
useConstructor = useConstructor,
outerInstance = outerInstance,
lenient = lenient
strictness = strictness
)
)!!
}
Expand All @@ -100,7 +101,8 @@ inline fun <reified T : Any> 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 <reified T : Any> mock(
extraInterfaces: Array<out KClass<out Any>>? = null,
Expand All @@ -112,9 +114,10 @@ inline fun <reified T : Any> mock(
verboseLogging: Boolean = false,
invocationListeners: Array<InvocationListener>? = 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>.(T) -> Unit
): T {
return Mockito.mock(
Expand All @@ -131,7 +134,7 @@ inline fun <reified T : Any> mock(
stubOnly = stubOnly,
useConstructor = useConstructor,
outerInstance = outerInstance,
lenient = lenient
strictness = strictness,
)
).apply { KStubbing(this).stubbing(this) }!!
}
Expand All @@ -151,7 +154,8 @@ inline fun <reified T : Any> 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<out KClass<out Any>>? = null,
Expand All @@ -163,9 +167,10 @@ fun withSettings(
verboseLogging: Boolean = false,
invocationListeners: Array<InvocationListener>? = 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) }
Expand All @@ -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 <reified T> mockStatic(): MockedStatic<T> {
return Mockito.mockStatic(T::class.java)
inline fun <reified T> mockStatic(
defaultAnswer: Answer<Any>? = null,
): MockedStatic<T> {
return Mockito.mockStatic(T::class.java, withSettings(defaultAnswer = defaultAnswer))
}

/**
Expand Down
52 changes: 52 additions & 0 deletions tests/src/test/kotlin/test/MockingTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ 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
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.*
Expand Down Expand Up @@ -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<SynchronousFunctions>()
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<SynchronousFunctions>(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<SynchronousFunctions>(strictness = Strictness.LENIENT)
whenever(result.intResult()).thenReturn(42)

/* Then */
// Verify no "Unnecessary stubbings detected" exception
session.finishMocking()
}

@Test
fun mockStubbing_withSettingsAPI_extraInterfaces() {
/* Given */
Expand Down Expand Up @@ -399,6 +444,13 @@ class MockingTest : TestBase() {
}
}

@Test
fun mockStatic_defaultAnswer_stubbing() {
mockStatic<SomeObject>(defaultAnswer = Mockito.CALLS_REAL_METHODS).use {
expect(SomeObject.aStaticMethodReturningString()).toBe("Some Value")
}
}

@Test
fun mockConstruction_basic() {
mockConstruction<Open>().use { mockedConstruction ->
Expand Down