Skip to content

Commit

Permalink
Prevent silent mis-stubbing (#479)
Browse files Browse the repository at this point in the history
Without this check, stubbing can silently be applied elsewhere.
This fix can only be applied in `KStubbing` as `when` does not accept the mock itself and thus, the issue is presented.
  • Loading branch information
wesalvaro authored Mar 7, 2023
1 parent 6d79682 commit 34cb898
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ package org.mockito.kotlin
import org.mockito.kotlin.internal.createInstance
import kotlinx.coroutines.runBlocking
import org.mockito.Mockito
import org.mockito.exceptions.misusing.NotAMockException
import org.mockito.stubbing.OngoingStubbing
import kotlin.reflect.KClass


inline fun <T> stubbing(
inline fun <T : Any> stubbing(
mock: T,
stubbing: KStubbing<T>.(T) -> Unit
) {
Expand All @@ -43,7 +44,10 @@ inline fun <T : Any> T.stub(stubbing: KStubbing<T>.(T) -> Unit): T {
return apply { KStubbing(this).stubbing(this) }
}

class KStubbing<out T>(val mock: T) {
class KStubbing<out T : Any>(val mock: T) {
init {
if(!mockingDetails(mock).isMock) throw NotAMockException("Stubbing target is not a mock!")
}

fun <R> on(methodCall: R): OngoingStubbing<R> = Mockito.`when`(methodCall)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fun <T> spy(value: T): T {
* Creates a spy of the real object, allowing for immediate stubbing.
* The spy calls <b>real</b> methods unless they are stubbed.
*/
inline fun <reified T> spy(value: T, stubbing: KStubbing<T>.(T) -> Unit): T {
inline fun <reified T : Any> spy(value: T, stubbing: KStubbing<T>.(T) -> Unit): T {
return spy(value)
.apply { KStubbing(this).stubbing(this) }!!
}
10 changes: 10 additions & 0 deletions tests/src/test/kotlin/test/OngoingStubbingTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,16 @@ class OngoingStubbingTest : TestBase() {
expect(mock.stringResult("B")).toBe("B")
}

@Test
fun stubbingRealObject() {
val notAMock = ""

/* Expect */
expectErrorWithMessage("is not a mock!").on {
notAMock.stub { }
}
}

@Test
fun stubbingTwiceWithCheckArgumentMatchers_throwsException() {
/* Expect */
Expand Down

0 comments on commit 34cb898

Please sign in to comment.