Turbine for Kotlin: Complete Guide to Testing Flow
\n\n1. What It Is and Why You Need It
\nThe Turbine library is a modern tool for testing coroutine data streams (Flow) in the Kotlin language. Developed by Cash App, Turbine solves one of the most painful problems when writing unit tests for asynchronous code: the complexity of checking value emissions from Flow, handling errors, and stream completion. Unlike standard approaches such as using kotlinx-coroutines-test with manual collection of elements, Turbine provides a declarative and intuitive API that makes tests readable and reliable.
Why do you need Turbine? Imagine you are writing a ViewModel that subscribes to a repository and transforms data into UI state. Without Turbine, you would have to manually create collectors, manage Jobs, and synchronize coroutines. Turbine automates this process: it creates a virtual coroutine, collects all emissions into a "turbine" (hence the name), and then allows you to check each value in order, ignoring unimportant intermediate states. This is especially useful when testing BehaviorSubject-like streams where only the final state matters.
\n\nThe library's main features include: checking emitted values in strict order, ignoring intermediate values using skip(), testing errors via awaitError(), checking stream completion via awaitComplete(), as well as working with channels (Channel) and StateFlow. Turbine integrates with any testing framework (JUnit, Kotest, Spek) and requires no additional configuration — just add the dependency and use testScope.
2. Installation
\nTo use Turbine in your project, add the following dependency to the build.gradle.kts (or build.gradle) file:
// build.gradle.kts\ndependencies {\n // For JVM projects\n testImplementation("app.cash.turbine:turbine:1.1.0")\n \n // If using kotlinx-coroutines-test (recommended)\n testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")\n}\n\n// For Android projects (in the android block)\nandroid {\n testOptions {\n unitTests.isReturnDefaultValues = true\n }\n}\n\n\nIf you are using Maven:
\n<dependency>\n <groupId>app.cash.turbine</groupId>\n <artifactId>turbine</artifactId>\n <version>1.1.0</version>\n <scope>test</scope>\n</dependency>\n\n\nMinimum requirements: Kotlin 1.9+, kotlinx-coroutines 1.8+. The library supports JVM, Android, JS, and Native (via Kotlin Multiplatform).
\n\n3. Quick Start
\nLet's look at a simple example: testing a Flow that emits three numbers.
\n\nimport app.cash.turbine.test\nimport kotlinx.coroutines.flow.flowOf\nimport kotlinx.coroutines.test.runTest\nimport org.junit.Test\n\nclass SimpleTurbineTest {\n\n @Test\n fun `test flow emits three values`() = runTest {\n val flow = flowOf(1, 2, 3)\n\n flow.test {\n // awaitItem() waits for the next emission and returns it\n assertEquals(1, awaitItem())\n assertEquals(2, awaitItem())\n assertEquals(3, awaitItem())\n\n // awaitComplete() checks that the stream completed without errors\n awaitComplete()\n }\n }\n}\n\n\nRun this test — it will pass successfully. Note: test is a suspend function that starts collecting the stream in a separate coroutine. All calls to awaitItem() block the current coroutine until the next element appears. If the stream completes earlier than expected, the test will fail with