Skip to content

Commit

Permalink
Support coroutines
Browse files Browse the repository at this point in the history
  • Loading branch information
nhaarman committed Feb 3, 2018
1 parent 9dfd896 commit 5fa30e1
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ out/
.idea/uiDesigner.xml
.idea/vcs.xml
.idea/workspace.xml

*.orig
17 changes: 17 additions & 0 deletions mockito-kotlin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ repositories {

dependencies {
compileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compileOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.3'

compile "org.mockito:mockito-core:2.13.0"

testCompile 'junit:junit:4.12'
testCompile 'com.nhaarman:expect.kt:1.0.0'

testCompile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.3'

testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.21"
}

dokka {
Expand All @@ -39,3 +49,10 @@ dokka {
}
}
javadoc.dependsOn dokka


kotlin {
experimental {
coroutines "enable"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package com.nhaarman.mockitokotlin2

import com.nhaarman.mockitokotlin2.internal.createInstance
import kotlinx.coroutines.experimental.runBlocking
import org.mockito.Mockito
import org.mockito.stubbing.OngoingStubbing
import kotlin.reflect.KClass
Expand All @@ -42,7 +43,7 @@ inline fun <T : Any> T.stub(stubbing: KStubbing<T>.(T) -> Unit): T {
return apply { KStubbing(this).stubbing(this) }
}

class KStubbing<out T>(private val mock: T) {
class KStubbing<out T>(val mock: T) {

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

Expand Down Expand Up @@ -74,4 +75,10 @@ class KStubbing<out T>(private val mock: T) {
)
}
}

fun <T : Any, R> KStubbing<T>.onBlocking(
m: suspend T.() -> R
): OngoingStubbing<R> {
return runBlocking { Mockito.`when`(mock.m()) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package com.nhaarman.mockitokotlin2

import com.nhaarman.mockitokotlin2.internal.createInstance
import kotlinx.coroutines.experimental.runBlocking
import org.mockito.InOrder
import org.mockito.Mockito
import org.mockito.verification.VerificationAfterDelay
Expand All @@ -41,6 +42,17 @@ fun <T> verify(mock: T): T {
return Mockito.verify(mock)!!
}

/**
* Verifies certain suspending behavior <b>happened once</b>.
*
* Warning: Only one method call can be verified in the function.
* Subsequent method calls are ignored!
*/
fun <T> verifyBlocking(mock: T, f: suspend T.() -> Unit) {
val m = Mockito.verify(mock)
runBlocking { m.f() }
}

/**
* Verifies certain behavior happened at least once / exact number of times / never.
*
Expand Down
158 changes: 158 additions & 0 deletions mockito-kotlin/src/test/kotlin/test/CoroutinesTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
@file:Suppress("EXPERIMENTAL_FEATURE_WARNING")

package test

import com.nhaarman.expect.expect
import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.verifyBlocking
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.runBlocking
import kotlinx.coroutines.experimental.withContext
import org.junit.Test


class CoroutinesTest {

@Test
fun stubbingSuspending() {
/* Given */
val m = mock<SomeInterface> {
onBlocking { suspending() } doReturn 42
}

/* When */
val result = runBlocking { m.suspending() }

/* Then */
expect(result).toBe(42)
}

@Test
fun stubbingSuspending_usingSuspendingFunction() {
/* Given */
val m = mock<SomeInterface> {
onBlocking { suspending() } doReturn runBlocking { SomeClass().result(42) }
}

/* When */
val result = runBlocking { m.suspending() }

/* Then */
expect(result).toBe(42)
}

@Test
fun stubbingSuspending_runBlocking() = runBlocking {
/* Given */
val m = mock<SomeInterface> {
onBlocking { suspending() } doReturn 42
}

/* When */
val result = m.suspending()

/* Then */
expect(result).toBe(42)
}

@Test
fun stubbingNonSuspending() {
/* Given */
val m = mock<SomeInterface> {
onBlocking { nonsuspending() } doReturn 42
}

/* When */
val result = m.nonsuspending()

/* Then */
expect(result).toBe(42)
}

@Test
fun stubbingNonSuspending_runBlocking() = runBlocking {
/* Given */
val m = mock<SomeInterface> {
onBlocking { nonsuspending() } doReturn 42
}

/* When */
val result = m.nonsuspending()

/* Then */
expect(result).toBe(42)
}

@Test
fun delayingResult() {
/* Given */
val m = SomeClass()

/* When */
val result = runBlocking { m.delaying() }

/* Then */
expect(result).toBe(42)
}

@Test
fun delayingResult_runBlocking() = runBlocking {
/* Given */
val m = SomeClass()

/* When */
val result = m.delaying()

/* Then */
expect(result).toBe(42)
}

@Test
fun verifySuspendFunctionCalled() {
/* Given */
val m = mock<SomeInterface>()

/* When */
runBlocking { m.suspending() }

/* Then */
runBlocking { verify(m).suspending() }
}

@Test
fun verifySuspendFunctionCalled_runBlocking() = runBlocking<Unit> {
val m = mock<SomeInterface>()

m.suspending()

verify(m).suspending()
}

@Test
fun verifySuspendFunctionCalled_verifyBlocking() {
val m = mock<SomeInterface>()

runBlocking { m.suspending() }

verifyBlocking(m) { suspending() }
}
}

interface SomeInterface {

suspend fun suspending(): Int
fun nonsuspending(): Int
}

class SomeClass {

suspend fun result(r: Int) = withContext(CommonPool) { r }

suspend fun delaying() = withContext(CommonPool) {
delay(100)
42
}
}
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
include 'mockito-kotlin'
include 'tests'
include 'tests'

0 comments on commit 5fa30e1

Please sign in to comment.