Readme Index
- Installation
- StoreFlow Core Api
- SideEffects
- Subscriber Aware StoreFlow
- Jetpack Compose Support
- Unit Test Support
Unit Test Support
Module: com.episode6.redux:test-support:1.0.1
Because StoreFlow launches a coroutine on init, unit-testing with kotlin’s new-ish runTest method is not entirely straightforward (creating a StoreFlow with a TestScope results in a UncompletedCoroutinesError since StoreFlow will intentionally never complete its Job until its CoroutineScope is explicitly cancelled).
To deal with this, we supply a StoreManager in the :test-support module. The StoreManager is used to create and shutdown the StoreFlow that is being tested.
Example:
private fun createStoreFlow(scope: CoroutineScope): StoreFlow<TrafficLightState> { /* */ }
@Test fun testGreenLight() = runTest {
val manager = StoreManager { createStoreFlow(this) }
val store: StoreFlow<TrafficLightState> = manager.store()
// test code
store.dispatch(SetGreenLight(true))
assertTrue(store.state.green)
// we must shutdown the StoreManager before the end of the test body
manager.shutdown()
}
We also offer a convenience method runStoreTest (that replaces runTest) that automatically shuts down the store at the end of the test…
@Test fun testGreenLight() = runStoreTest(::createStoreFlow) { store ->
// test code
store.dispatch(SetGreenLight(true))
assertTrue(store.state.green)
}
Testing individual SideEffects
While integration tests of a fully-formed StoreFlow offer the most value, you may want to test SideEffects individually to validate their output. To assist with this, we offer the SideEffectTestContext class and SideEffect.testOutput(SideEffectTestContext): Flow<Action> method. The SideEffectTestContext lets you emit Actions and control the currentState() that is available to the SideEffect. We can then test the emissions of the resulting Flow using Turbine (or by manually collecting from it).
Example:
class SideEffectTest {
val context = SideEffectTestContext(defaultState = TrafficLightState())
@Test fun testGreenLightEffect() = runTest {
val sideEffect = greenLightSideEffect() // from our SideEffects example code
val testOutput: Flow<Action> = sideEffect.testOutput(context)
testOutput.test { // Flow.test function is part of the Turbine library
// use context to send actions through the SideEffect
context.actionsFlow.emit(SetGreenLight(true))
advanceTimeBy(30000L)
// awaitItem is part of the Turbine library
assertEquals(awaitItem(), SetGreenLight(false))
assertEquals(awaitItem(), SetYellowLight(true))
}
}
}