0Pricing
Kotlin Academy · Pelajaran

Menguji StateFlow dan SharedFlow dengan Turbine

Tulislah unit test untuk status berbasis Flow menggunakan pustaka pengujian Turbine.

Menguji StateFlow dan SharedFlow dengan Turbine adalah pelajaran Kotlin Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Kotlin Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Kotlin Academy mencakup 4 pelajaran total.

Mengapa Turbine?

Turbine adalah pustaka pengujian untuk Kotlin Flow yang memudahkan verifikasi emisi. Tanpanya, pengujian aliran memerlukan pengumpulan saluran secara manual dengan batas waktu.

// Add to test dependencies:
// testImplementation("app.cash.turbine:turbine:1.0.0")
// testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun main() { println("Turbine + runTest = clean flow testing") }

Pengujian Aliran Dasar dengan test()

flow.test { } mengumpulkan aliran dan memungkinkan Anda memverifikasi setiap emisi menggunakan awaitItem(), awaitComplete(), dan awaitError().

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testBasicFlow() = runTest {
    val flow = flowOf(1, 2, 3)
    flow.test {
        assertEquals(1, awaitItem())
        assertEquals(2, awaitItem())
        assertEquals(3, awaitItem())
        awaitComplete()
    }
}

Menguji StateFlow

StateFlow selalu memancarkan nilainya saat ini ketika dikumpulkan. awaitItem() milik Turbine menangkap emisi awal tersebut.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testStateFlow() = runTest {
    val state = MutableStateFlow("loading")
    state.test {
        assertEquals("loading", awaitItem())  // initial value
        state.value = "success"
        assertEquals("success", awaitItem())
        cancelAndIgnoreRemainingEvents()
    }
}

Menguji Peristiwa SharedFlow

SharedFlow dengan replay=0 hanya memancarkan peristiwa yang terjadi setelahnya. Mulailah mengumpulkan terlebih dahulu, lalu lakukan emisi.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testSharedFlow() = runTest {
    val events = MutableSharedFlow<String>()
    events.test {
        events.emit("LoginSuccess")
        assertEquals("LoginSuccess", awaitItem())
        events.emit("Navigate")
        assertEquals("Navigate", awaitItem())
        cancelAndIgnoreRemainingEvents()
    }
}

runTest untuk Waktu Virtual

runTest menggunakan waktu virtual — pemanggilan delay() memajukan waktu virtual secara langsung, sehingga pengujian dengan penundaan berjalan cepat.

import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
import app.cash.turbine.*
fun testDelayedFlow() = runTest {
    val flow = flow {
        delay(1000)  // virtual — runs instantly
        emit("done")
    }
    flow.test {
        assertEquals("done", awaitItem())
        awaitComplete()
    }
}

awaitError untuk Menguji Pengecualian

awaitError() memverifikasi bahwa aliran berakhir dengan pengecualian. Gunakan bersama tipe pengecualian yang diharapkan.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testFlowError() = runTest {
    val flow = flow {
        emit(1)
        throw RuntimeException("stream error")
    }
    flow.test {
        assertEquals(1, awaitItem())
        val error = awaitError()
        assertEquals("stream error", error.message)
    }
}

expectNoEvents dan cancelAndIgnoreRemainingEvents

expectNoEvents() memverifikasi bahwa tidak ada yang dipancarkan. cancelAndIgnoreRemainingEvents() membatalkan pengumpulan dan mengabaikan emisi yang masih tertunda.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testNoEvents() = runTest {
    val flow = MutableSharedFlow<Int>()
    flow.test {
        expectNoEvents()  // nothing emitted yet
        flow.emit(1)
        assertEquals(1, awaitItem())
        cancelAndIgnoreRemainingEvents()
    }
}

Menguji ViewModel dengan Turbine

Uji StateFlow milik ViewModel dengan menyuntikkan repositori tiruan dan memverifikasi perubahan status.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
sealed class State { object Loading : State(); data class Data(val v: String) : State() }
class FakeRepo { suspend fun fetch() = "result" }
class VM(repo: FakeRepo, scope: kotlinx.coroutines.CoroutineScope) {
    private val _s = MutableStateFlow<State>(State.Loading)
    val state = _s.asStateFlow()
    init { scope.launch { _s.value = State.Data(repo.fetch()) } }
}
fun testVM() = runTest {
    val vm = VM(FakeRepo(), backgroundScope)
    vm.state.test {
        assertEquals(State.Loading, awaitItem())
        val data = awaitItem() as State.Data
        assertEquals("result", data.v)
        cancelAndIgnoreRemainingEvents()
    }
}

Beberapa Pengumpul dengan turbineScope

turbineScope { } memungkinkan Anda menguji beberapa aliran secara bersamaan, masing-masing dengan instans Turbine sendiri.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testMultipleFlows() = runTest {
    val a = MutableStateFlow(1)
    val b = MutableStateFlow("x")
    turbineScope {
        val aTurbine = a.testIn(backgroundScope)
        val bTurbine = b.testIn(backgroundScope)
        assertEquals(1, aTurbine.awaitItem())
        assertEquals("x", bTurbine.awaitItem())
        a.value = 2
        assertEquals(2, aTurbine.awaitItem())
        aTurbine.cancelAndIgnoreRemainingEvents()
        bTurbine.cancelAndIgnoreRemainingEvents()
    }
}

Menguji Operator Aliran

Uji perilaku operator aliran khusus dan transformasinya secara terpisah menggunakan Turbine.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testOperators() = runTest {
    (1..5).asFlow()
        .filter { it % 2 == 0 }
        .map { it * 10 }
        .test {
            assertEquals(20, awaitItem())
            assertEquals(40, awaitItem())
            awaitComplete()
        }
}

Pengujian dengan Pemajuan Waktu Tiruan

Gunakan testScheduler.advanceTimeBy() untuk mengendalikan waktu virtual secara tepat dalam pengujian yang melibatkan delay.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testTimedFlow() = runTest {
    val flow = flow {
        emit("start")
        delay(500)
        emit("end")
    }
    flow.test {
        assertEquals("start", awaitItem())
        testScheduler.advanceTimeBy(500)
        assertEquals("end", awaitItem())
        awaitComplete()
    }
}

Kesalahan Umum

Selalu batalkan Turbine di akhir pengujian aliran panas. Lupa memanggil cancelAndIgnoreRemainingEvents() menyebabkan pengujian menunggu peristiwa lain dan akhirnya macet.

import app.cash.turbine.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.test.*
fun testGoodPractice() = runTest {
    val state = MutableStateFlow(0)
    state.test {
        awaitItem()  // initial 0
        state.value = 1
        awaitItem()  // 1
        // Always cancel hot flows:
        cancelAndIgnoreRemainingEvents()
    }
}

Pemeriksaan Cepat

Fungsi Turbine mana yang mengumpulkan item yang dipancarkan berikutnya dan melemparkan kesalahan jika aliran selesai atau mengalami kesalahan terlebih dahulu?

Ringkasan

Turbine menyederhanakan pengujian Flow dengan awaitItem(), awaitComplete(), dan awaitError(). Gunakan runTest untuk waktu virtual. Selalu batalkan pengujian aliran panas dengan cancelAndIgnoreRemainingEvents().

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Menguji StateFlow dan SharedFlow dengan Turbine” gratis?

Ya — teks lengkap “Menguji StateFlow dan SharedFlow dengan Turbine” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Kotlin Academy, upgrade ke CoddyKit PRO. Kursus Kotlin Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Menguji StateFlow dan SharedFlow dengan Turbine”?

Tulislah unit test untuk status berbasis Flow menggunakan pustaka pengujian Turbine. Kamu berlatih Kotlin Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Kotlin Academy?

Tidak diperlukan pengalaman sebelumnya. Kotlin Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Menguji StateFlow dan SharedFlow dengan Turbine” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Kotlin Academy ini?

Ya. Setiap pelajaran Kotlin Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. StateFlow: Penampung Status Aktif untuk UI
  2. SharedFlow: Bus Peristiwa dan Peristiwa Sekali Jalan
  3. Mengubah Flow Dingin Menjadi Aktif dengan shareIn dan stateIn
  4. Menguji StateFlow dan SharedFlow dengan Turbine
← Kembali ke Kotlin Academy