Skip to content

Commit 150250a

Browse files
naoussinappy29
andauthored
KTLN-575 Testing Flow in Kotlin (#1137)
* Added unit tests * changes to code * code changes * code fixes * code fixes * code fixes * Added code * fixes * fixes * fixes * fixes --------- Co-authored-by: nappy29 <[email protected]>
1 parent be678ca commit 150250a

File tree

2 files changed

+163
-6
lines changed

2 files changed

+163
-6
lines changed

core-kotlin-modules/core-kotlin-flows/pom.xml

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<project xmlns="http://maven.apache.org/POM/4.0.0"
2-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
45
<modelVersion>4.0.0</modelVersion>
56
<artifactId>core-kotlin-flows</artifactId>
67
<name>core-kotlin-flows</name>
78
<packaging>jar</packaging>
8-
99
<parent>
1010
<groupId>com.baeldung</groupId>
1111
<artifactId>core-kotlin-modules</artifactId>
@@ -21,17 +21,30 @@
2121
<dependency>
2222
<groupId>org.jetbrains.kotlinx</groupId>
2323
<artifactId>kotlinx-coroutines-reactor</artifactId>
24-
<version>1.9.0</version>
24+
<version>${kotlinx.coroutines.version}</version>
25+
2526
</dependency>
2627
<dependency>
2728
<groupId>io.projectreactor</groupId>
2829
<artifactId>reactor-core</artifactId>
29-
<version>3.6.10</version>
30+
<version>${reactor.version}</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.jetbrains.kotlinx</groupId>
34+
<artifactId>kotlinx-coroutines-core</artifactId>
35+
<version>${kotlinx.coroutines.version}</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.jetbrains.kotlinx</groupId>
39+
<artifactId>kotlinx-coroutines-test</artifactId>
40+
<version>${kotlinx.coroutines.version}</version>
41+
<scope>test</scope>
3042
</dependency>
3143
</dependencies>
3244

3345
<properties>
3446
<junit.version>4.13.2</junit.version>
47+
<kotlinx.coroutines.version>1.7.3</kotlinx.coroutines.version>
48+
<reactor.version>3.4.11</reactor.version>
3549
</properties>
36-
3750
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package com.baeldung.flowTest
2+
3+
import kotlinx.coroutines.*
4+
import kotlinx.coroutines.channels.onFailure
5+
import kotlinx.coroutines.flow.*
6+
import kotlinx.coroutines.test.advanceTimeBy
7+
import kotlinx.coroutines.test.runTest
8+
import org.junit.jupiter.api.Assertions.assertEquals
9+
import org.junit.jupiter.api.Test
10+
import org.junit.jupiter.api.assertThrows
11+
import java.util.concurrent.CancellationException
12+
13+
class FlowTestUnitTest {
14+
15+
@Test
16+
fun `simpleFlow should emit 1 2 3`() = runTest {
17+
val flow = simpleFlow().toList()
18+
19+
assertEquals(listOf(1, 2, 3), flow)
20+
}
21+
22+
@Test
23+
fun `transformedFlow should multiply values by 2`() = runTest {
24+
val result = transformedFlow().toList()
25+
assertEquals(listOf(2, 4, 6), result)
26+
}
27+
28+
@Test
29+
fun `errorFlow should emit values and recover from exception`() = runTest {
30+
val emittedValues = errorFlow().toList()
31+
32+
assertEquals(listOf(1, 2, -1), emittedValues)
33+
}
34+
35+
@Test
36+
fun `implicitCancellationFlow stops on cancellation`() = runTest {
37+
val emittedValues = mutableListOf<Int>()
38+
val job = launch {
39+
implicitCancellationFlow().collect { emittedValues.add(it) }
40+
}
41+
42+
advanceTimeBy(600)
43+
job.cancelAndJoin()
44+
45+
assertEquals(listOf(1,2), emittedValues)
46+
}
47+
48+
@Test
49+
fun `cancellableFlow stops emitting after external cancellation`() = runTest {
50+
val emittedValues = mutableListOf<Int>()
51+
val job = launch {
52+
cancellableFlow().collect { emittedValues.add(it) }
53+
}
54+
55+
advanceTimeBy(2000)
56+
job.cancelAndJoin()
57+
58+
assertEquals(listOf(0, 1), emittedValues)
59+
}
60+
61+
@Test
62+
fun `uncancellableFlow ensures cleanup occurs`() = runTest {
63+
val emittedValues = mutableListOf<Int>()
64+
val job = launch {
65+
uncancellableFlow().collect { emittedValues.add(it) }
66+
}
67+
68+
advanceTimeBy(400)
69+
job.cancelAndJoin()
70+
71+
assertEquals(listOf(1), emittedValues)
72+
}
73+
74+
@Test
75+
fun `delayedFlow should handle delayed emissions`() = runTest {
76+
val result = delayedFlow().toList()
77+
assertEquals(listOf(1, 2), result)
78+
}
79+
}
80+
81+
fun simpleFlow(): Flow<Int> = flow {
82+
emit(1)
83+
emit(2)
84+
emit(3)
85+
}
86+
87+
fun transformedFlow(): Flow<Int> = flow {
88+
emit(1)
89+
emit(2)
90+
emit(3)
91+
}.map { it * 2 }
92+
93+
fun errorFlow(): Flow<Int> = flow {
94+
emit(1)
95+
emit(2)
96+
throw Exception("Test Exception")
97+
}.catch { e ->
98+
emit(-1)
99+
}
100+
101+
fun cancellableFlow(): Flow<Int> = flow {
102+
try {
103+
repeat(5) {
104+
emit(it)
105+
delay(1000)
106+
}
107+
} finally {
108+
println("Cleanup: Emitting -1")
109+
emit(-1)
110+
}
111+
}.onEach { value ->
112+
if (value == 2) throw CancellationException("Flow was canceled at value 2")
113+
}.onCompletion { cause ->
114+
if (cause is CancellationException) {
115+
println("Flow canceled: Releasing resources")
116+
}
117+
}
118+
119+
fun delayedFlow(): Flow<Int> = flow {
120+
delay(500)
121+
emit(1)
122+
delay(500)
123+
emit(2)
124+
}
125+
126+
fun implicitCancellationFlow(): Flow<Int> = flow {
127+
emit(1)
128+
delay(500)
129+
emit(2)
130+
delay(500)
131+
emit(3)
132+
}
133+
134+
fun uncancellableFlow(): Flow<Int> = flow {
135+
try {
136+
emit(1)
137+
delay(500)
138+
emit(2)
139+
} finally {
140+
withContext(NonCancellable) {
141+
println("Releasing resources")
142+
}
143+
}
144+
}

0 commit comments

Comments
 (0)