Skip to content

Commit 93934a1

Browse files
m-koopsTimvdLippe
authored andcommitted
Add more test cases focussing on the stubbing of suspend functions.
1 parent 3e98346 commit 93934a1

File tree

3 files changed

+475
-6
lines changed

3 files changed

+475
-6
lines changed

tests/src/test/kotlin/test/Classes.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,13 @@ interface SuspendFunctions {
108108
suspend fun intResult(i: Int): Int
109109
suspend fun stringResult(): String
110110
suspend fun stringResult(s: String): String
111+
suspend fun stringResult(s1: String, s2: String): String
112+
suspend fun nullableStringResult(): String?
113+
suspend fun builderMethod(): SuspendFunctions
111114
}
112115

113116
@JvmInline
114-
value class ValueClass(private val content: String)
117+
value class ValueClass(val content: String)
115118

116119
@JvmInline
117120
value class NestedValueClass(val value: ValueClass)
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
package test
2+
3+
import com.nhaarman.expect.expect
4+
import kotlinx.coroutines.runBlocking
5+
import kotlinx.coroutines.test.runTest
6+
import org.junit.Ignore
7+
import org.junit.Test
8+
import org.mockito.Mockito
9+
import org.mockito.kotlin.any
10+
import org.mockito.kotlin.doAnswer
11+
import org.mockito.kotlin.doReturn
12+
import org.mockito.kotlin.doReturnConsecutively
13+
import org.mockito.kotlin.doThrow
14+
import org.mockito.kotlin.mock
15+
import org.mockito.stubbing.Answer
16+
17+
class CoroutinesOngoingStubbingTest {
18+
@Test
19+
fun `should stub suspendable function call`() {
20+
/* Given */
21+
val mock = mock<SuspendFunctions> {
22+
onBlocking { stringResult() } doReturn "A"
23+
}
24+
25+
/* When */
26+
val result = runBlocking { mock.stringResult() }
27+
28+
/* Then */
29+
expect(result).toBe("A")
30+
}
31+
32+
@Test
33+
fun `should stub suspendable function call within a coroutine scope`() = runTest {
34+
/* Given */
35+
val mock = mock<SuspendFunctions> {
36+
onBlocking { stringResult() } doReturn "A"
37+
}
38+
39+
/* When */
40+
val result = mock.stringResult()
41+
42+
/* Then */
43+
expect(result).toBe("A")
44+
}
45+
46+
@Test
47+
fun `should stub consecutive suspendable function calls`() {
48+
/* Given */
49+
val mock = mock<SuspendFunctions> {
50+
onBlocking { stringResult() }.doReturn("A", "B", "C")
51+
}
52+
53+
/* When */
54+
val result = runBlocking {
55+
(1..3).map { _ ->
56+
mock.stringResult()
57+
}
58+
}
59+
60+
/* Then */
61+
expect(result).toBe(listOf("A", "B", "C"))
62+
}
63+
64+
@Test
65+
fun `should stub consecutive suspendable function calls by a list of answers`() {
66+
/* Given */
67+
val mock = mock<SuspendFunctions> {
68+
onBlocking { stringResult() } doReturnConsecutively listOf("A", "B", "C")
69+
}
70+
71+
/* When */
72+
val result = runBlocking {
73+
(1..3).map { _ ->
74+
mock.stringResult()
75+
}
76+
}
77+
78+
/* Then */
79+
expect(result).toBe(listOf("A", "B", "C"))
80+
}
81+
82+
@Ignore("Default answers do not yet work for coroutines, see https://github.com/mockito/mockito-kotlin/issues/550")
83+
@Test
84+
fun `should stub builder method returning mock itself via defaultAnswer`() {
85+
/* Given */
86+
val mock = mock<SuspendFunctions>(defaultAnswer = Mockito.RETURNS_SELF)
87+
88+
/* When */
89+
val result = runBlocking { mock.builderMethod() }
90+
91+
/* Then */
92+
expect(result).toBeTheSameAs(mock)
93+
}
94+
95+
@Ignore("Default answers do not yet work for coroutines, see https://github.com/mockito/mockito-kotlin/issues/550")
96+
@Test
97+
fun `should stub builder method returning mock itself via answer`() {
98+
/* Given */
99+
val mock = mock<SuspendFunctions> {
100+
onBlocking { builderMethod() } doAnswer Mockito.RETURNS_SELF
101+
}
102+
103+
/* When */
104+
val result = runBlocking { mock.builderMethod() }
105+
106+
/* Then */
107+
expect(result).toBeTheSameAs(mock)
108+
}
109+
110+
@Test
111+
fun `should stub builder method returning mock itself`() {
112+
/* Given */
113+
val mock = mock<SuspendFunctions> { mock ->
114+
onBlocking { builderMethod() } doReturn mock
115+
}
116+
117+
/* When */
118+
val result = runBlocking { mock.builderMethod() }
119+
120+
/* Then */
121+
expect(result).toBe(mock)
122+
}
123+
124+
@Test
125+
fun `should stub suspendable function call with nullable result`() {
126+
/* Given */
127+
val mock = mock<SuspendFunctions> {
128+
onBlocking { nullableStringResult() } doReturn "Test"
129+
}
130+
131+
/* When */
132+
val result = runBlocking { mock.nullableStringResult() }
133+
134+
/* Then */
135+
expect(result).toBe("Test")
136+
}
137+
138+
@Test
139+
fun `should throw exception instance on suspendable function call`() {
140+
/* Given */
141+
val mock = mock<SuspendFunctions> {
142+
onBlocking { builderMethod() } doThrow IllegalArgumentException()
143+
}
144+
145+
/* When, Then */
146+
runBlocking {
147+
assertThrows<IllegalArgumentException> {
148+
mock.builderMethod()
149+
}
150+
}
151+
}
152+
153+
@Test
154+
fun `should throw exception class on suspendable function call`() {
155+
/* Given */
156+
val mock = mock<SuspendFunctions> {
157+
onBlocking { builderMethod() } doThrow IllegalArgumentException::class
158+
}
159+
160+
/* When, Then */
161+
runBlocking {
162+
assertThrows<IllegalArgumentException> {
163+
mock.builderMethod()
164+
}
165+
}
166+
}
167+
168+
@Test
169+
fun `should throw exception instances on consecutive suspendable function calls`() {
170+
/* Given */
171+
val mock = mock<SuspendFunctions> {
172+
onBlocking { builderMethod() }.doThrow(
173+
IllegalArgumentException(),
174+
UnsupportedOperationException()
175+
)
176+
}
177+
178+
/* When, Then */
179+
runBlocking {
180+
assertThrows<IllegalArgumentException> {
181+
mock.builderMethod()
182+
}
183+
assertThrows<UnsupportedOperationException> {
184+
mock.builderMethod()
185+
}
186+
}
187+
}
188+
189+
@Test
190+
fun `should throw exception classes on consecutive suspendable function calls`() {
191+
/* Given */
192+
val mock = mock<SuspendFunctions> {
193+
onBlocking { builderMethod() }.doThrow(
194+
IllegalArgumentException::class,
195+
UnsupportedOperationException::class
196+
)
197+
}
198+
199+
/* When, Then */
200+
runBlocking {
201+
assertThrows<IllegalArgumentException> {
202+
mock.builderMethod()
203+
}
204+
assertThrows<UnsupportedOperationException> {
205+
mock.builderMethod()
206+
}
207+
}
208+
}
209+
210+
@Test
211+
fun `should stub suspendable function call with result from answer instance`() {
212+
/* Given */
213+
val answer: Answer<String> = Answer { "result" }
214+
val mock = mock<SuspendFunctions> {
215+
onBlocking { stringResult() } doAnswer answer
216+
}
217+
218+
/* When */
219+
220+
val result = runBlocking { mock.stringResult() }
221+
222+
/* Then */
223+
expect(result).toBe("result")
224+
}
225+
226+
@Test
227+
fun `should stub suspendable function call with result from lambda`() {
228+
/* Given */
229+
val mock = mock<SuspendFunctions> {
230+
onBlocking { stringResult() } doAnswer { "result" }
231+
}
232+
233+
/* When */
234+
val result = runBlocking { mock.stringResult() }
235+
236+
/* Then */
237+
expect(result).toBe("result")
238+
}
239+
240+
@Test
241+
fun `should stub suspendable function call with result from lambda with argument`() {
242+
/* Given */
243+
val mock = mock<SuspendFunctions> {
244+
onBlocking { stringResult(any()) } doAnswer { "${it.arguments[0]}-result" }
245+
}
246+
247+
/* When */
248+
val result = runBlocking { mock.stringResult("argument") }
249+
250+
/* Then */
251+
expect(result).toBe("argument-result")
252+
}
253+
254+
@Test
255+
fun `should stub suspendable function call with result from lambda with deconstructed argument`() {
256+
/* Given */
257+
val mock = mock<SuspendFunctions> {
258+
onBlocking { stringResult(any()) } doAnswer { (s: String) -> "$s-result" }
259+
}
260+
261+
/* When */
262+
val result = runBlocking { mock.stringResult("argument") }
263+
264+
/* Then */
265+
expect(result).toBe("argument-result")
266+
}
267+
268+
@Test
269+
fun `should stub suspendable function call with result from lambda with deconstructed arguments`() {
270+
/* Given */
271+
val mock = mock<SuspendFunctions> {
272+
onBlocking { stringResult(any(), any()) } doAnswer { (a: String, b: String) ->
273+
"$a + $b"
274+
}
275+
}
276+
277+
/* When */
278+
val result = runBlocking { mock.stringResult("apple", "banana") }
279+
280+
/* Then */
281+
expect(result).toBe("apple + banana")
282+
}
283+
}

0 commit comments

Comments
 (0)