testing-flows-with-turbine

Assert Flow emissions in Android/Kotlin tests using Turbine's ReceiveTurbine API.

303|10|Updated May 15, 2026
One-click install
npx skills add https://github.com/skydoves/android-testing-skills --skill testing-flows-with-turbine
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: testing-flows-with-turbine
Source: https://github.com/skydoves/android-testing-skills/tree/main/jvm-tests/coroutines/testing-flows-with-turbine
Command: npx skills add https://github.com/skydoves/android-testing-skills --skill testing-flows-with-turbine

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve?

This Skill prevents Flow-based tests from hanging when asserting emissions from hot streams like StateFlow and SharedFlow by providing a one-at-a-time, cancellation-safe assertion workflow.

Core Features & Use Cases

  • Assert ordered emissions without toList(): Use flow.test { ... } / testIn(...) to await items, completion, or errors while ensuring no unconsumed events remain.
  • Correctly handle hot vs cold Flow behavior: Avoid waiting for completion on hot flows and instead use cancel() or cancelAndIgnoreRemainingEvents() to end the test deterministically.
  • Support multi-flow assertions: Use turbineScope and testIn to interleave assertions across multiple flows in the same test.
  • Also verify non-Flow callbacks: Use the standalone Turbine<T>() channel to capture listener/callback invocations with the same awaitItem()-style vocabulary.

Example use case

You have a ViewModel exposing uiState: StateFlow<UiState> and events: SharedFlow<Event> and you need to assert the initial seed value, the subsequent loading and success states, and a one-shot event in a single run without the test stalling.

Quick Start

Ask the AI to show how to write a runTest using vm.uiState.test { ... } that asserts the StateFlow seed, awaits the next two emissions, and finishes with cancelAndIgnoreRemainingEvents() to avoid hanging.

Frequently Asked Questions about testing-flows-with-turbine

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
Why does my Kotlin StateFlow test hang when collecting emissions with toList()?

StateFlow and SharedFlow are hot streams that never complete, causing blocking collection helpers like toList() to hang indefinitely. Using Turbine's cancellation-safe assertion workflow awaits emissions one at a time and ends tests deterministically with cancel() or cancelAndIgnoreRemainingEvents().

How do I assert ordered emissions from multiple Kotlin Flows in a single test?

You can interleave assertions across multiple Kotlin Flows in a single test by using turbineScope and testIn. This multi-flow testing approach allows you to await items and verify emissions from different StateFlow or SharedFlow instances concurrently without stalling.

Can I use Turbine to verify non-Flow callbacks or listeners in Kotlin tests?

Yes, you can verify non-Flow callbacks using a standalone Turbine<T> channel. It captures listener invocations and provides the same awaitItem()-style assertion vocabulary used for Flow testing, allowing you to assert callback events safely.

What is the best way to test ViewModel StateFlow and SharedFlow without blocking?

The best way to test ViewModel StateFlow and SharedFlow without blocking is using Turbine's ReceiveTurbine API with wall-clock timeouts inside runTest. This approach safely asserts the initial seed, awaits subsequent emissions, and checks that all events are consumed.

How do I avoid unconsumed event errors when testing hot SharedFlow streams?

To avoid unconsumed event errors when testing hot SharedFlow streams, you should use cancelAndIgnoreRemainingEvents() at the end of your test block. This ensures the test finishes deterministically without hanging on hot streams that never complete.

Does Turbine support testing cold Flows alongside hot StateFlows in Android?

Yes, Turbine supports testing both cold Flows and hot StateFlows in Android. By using the flow.test { ... } API, you can await items, completion, or errors for cold flows, while applying cancellation contracts for hot flows to ensure no unconsumed events remain.