Skip to content

Commit d4b8fec

Browse files
authored
Merge pull request #239 from nhaarman/coroutines
Support coroutines
2 parents 9dfd896 + 5fa30e1 commit d4b8fec

File tree

6 files changed

+198
-2
lines changed

6 files changed

+198
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ out/
1818
.idea/uiDesigner.xml
1919
.idea/vcs.xml
2020
.idea/workspace.xml
21+
22+
*.orig

mockito-kotlin/build.gradle

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,17 @@ repositories {
2525

2626
dependencies {
2727
compileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
28+
compileOnly 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.3'
29+
2830
compile "org.mockito:mockito-core:2.13.0"
31+
32+
testCompile 'junit:junit:4.12'
33+
testCompile 'com.nhaarman:expect.kt:1.0.0'
34+
35+
testCompile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
36+
testCompile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.19.3'
37+
38+
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.21"
2939
}
3040

3141
dokka {
@@ -39,3 +49,10 @@ dokka {
3949
}
4050
}
4151
javadoc.dependsOn dokka
52+
53+
54+
kotlin {
55+
experimental {
56+
coroutines "enable"
57+
}
58+
}

mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/KStubbing.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package com.nhaarman.mockitokotlin2
2727

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

45-
class KStubbing<out T>(private val mock: T) {
46+
class KStubbing<out T>(val mock: T) {
4647

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

@@ -74,4 +75,10 @@ class KStubbing<out T>(private val mock: T) {
7475
)
7576
}
7677
}
78+
79+
fun <T : Any, R> KStubbing<T>.onBlocking(
80+
m: suspend T.() -> R
81+
): OngoingStubbing<R> {
82+
return runBlocking { Mockito.`when`(mock.m()) }
83+
}
7784
}

mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/Verification.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
package com.nhaarman.mockitokotlin2
2727

2828
import com.nhaarman.mockitokotlin2.internal.createInstance
29+
import kotlinx.coroutines.experimental.runBlocking
2930
import org.mockito.InOrder
3031
import org.mockito.Mockito
3132
import org.mockito.verification.VerificationAfterDelay
@@ -41,6 +42,17 @@ fun <T> verify(mock: T): T {
4142
return Mockito.verify(mock)!!
4243
}
4344

45+
/**
46+
* Verifies certain suspending behavior <b>happened once</b>.
47+
*
48+
* Warning: Only one method call can be verified in the function.
49+
* Subsequent method calls are ignored!
50+
*/
51+
fun <T> verifyBlocking(mock: T, f: suspend T.() -> Unit) {
52+
val m = Mockito.verify(mock)
53+
runBlocking { m.f() }
54+
}
55+
4456
/**
4557
* Verifies certain behavior happened at least once / exact number of times / never.
4658
*
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
@file:Suppress("EXPERIMENTAL_FEATURE_WARNING")
2+
3+
package test
4+
5+
import com.nhaarman.expect.expect
6+
import com.nhaarman.mockitokotlin2.doReturn
7+
import com.nhaarman.mockitokotlin2.mock
8+
import com.nhaarman.mockitokotlin2.verify
9+
import com.nhaarman.mockitokotlin2.verifyBlocking
10+
import kotlinx.coroutines.experimental.CommonPool
11+
import kotlinx.coroutines.experimental.delay
12+
import kotlinx.coroutines.experimental.runBlocking
13+
import kotlinx.coroutines.experimental.withContext
14+
import org.junit.Test
15+
16+
17+
class CoroutinesTest {
18+
19+
@Test
20+
fun stubbingSuspending() {
21+
/* Given */
22+
val m = mock<SomeInterface> {
23+
onBlocking { suspending() } doReturn 42
24+
}
25+
26+
/* When */
27+
val result = runBlocking { m.suspending() }
28+
29+
/* Then */
30+
expect(result).toBe(42)
31+
}
32+
33+
@Test
34+
fun stubbingSuspending_usingSuspendingFunction() {
35+
/* Given */
36+
val m = mock<SomeInterface> {
37+
onBlocking { suspending() } doReturn runBlocking { SomeClass().result(42) }
38+
}
39+
40+
/* When */
41+
val result = runBlocking { m.suspending() }
42+
43+
/* Then */
44+
expect(result).toBe(42)
45+
}
46+
47+
@Test
48+
fun stubbingSuspending_runBlocking() = runBlocking {
49+
/* Given */
50+
val m = mock<SomeInterface> {
51+
onBlocking { suspending() } doReturn 42
52+
}
53+
54+
/* When */
55+
val result = m.suspending()
56+
57+
/* Then */
58+
expect(result).toBe(42)
59+
}
60+
61+
@Test
62+
fun stubbingNonSuspending() {
63+
/* Given */
64+
val m = mock<SomeInterface> {
65+
onBlocking { nonsuspending() } doReturn 42
66+
}
67+
68+
/* When */
69+
val result = m.nonsuspending()
70+
71+
/* Then */
72+
expect(result).toBe(42)
73+
}
74+
75+
@Test
76+
fun stubbingNonSuspending_runBlocking() = runBlocking {
77+
/* Given */
78+
val m = mock<SomeInterface> {
79+
onBlocking { nonsuspending() } doReturn 42
80+
}
81+
82+
/* When */
83+
val result = m.nonsuspending()
84+
85+
/* Then */
86+
expect(result).toBe(42)
87+
}
88+
89+
@Test
90+
fun delayingResult() {
91+
/* Given */
92+
val m = SomeClass()
93+
94+
/* When */
95+
val result = runBlocking { m.delaying() }
96+
97+
/* Then */
98+
expect(result).toBe(42)
99+
}
100+
101+
@Test
102+
fun delayingResult_runBlocking() = runBlocking {
103+
/* Given */
104+
val m = SomeClass()
105+
106+
/* When */
107+
val result = m.delaying()
108+
109+
/* Then */
110+
expect(result).toBe(42)
111+
}
112+
113+
@Test
114+
fun verifySuspendFunctionCalled() {
115+
/* Given */
116+
val m = mock<SomeInterface>()
117+
118+
/* When */
119+
runBlocking { m.suspending() }
120+
121+
/* Then */
122+
runBlocking { verify(m).suspending() }
123+
}
124+
125+
@Test
126+
fun verifySuspendFunctionCalled_runBlocking() = runBlocking<Unit> {
127+
val m = mock<SomeInterface>()
128+
129+
m.suspending()
130+
131+
verify(m).suspending()
132+
}
133+
134+
@Test
135+
fun verifySuspendFunctionCalled_verifyBlocking() {
136+
val m = mock<SomeInterface>()
137+
138+
runBlocking { m.suspending() }
139+
140+
verifyBlocking(m) { suspending() }
141+
}
142+
}
143+
144+
interface SomeInterface {
145+
146+
suspend fun suspending(): Int
147+
fun nonsuspending(): Int
148+
}
149+
150+
class SomeClass {
151+
152+
suspend fun result(r: Int) = withContext(CommonPool) { r }
153+
154+
suspend fun delaying() = withContext(CommonPool) {
155+
delay(100)
156+
42
157+
}
158+
}

settings.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
include 'mockito-kotlin'
2-
include 'tests'
2+
include 'tests'

0 commit comments

Comments
 (0)