Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

romychab/flow-test

Repository files navigation

Flow Test

A tiny library for easier testing of Kotlin Flows in a sequential way, without direct usage of backgroundScope.launch { ... }.

Maven Central License: Apache 2

Installation

// flowtest library:
testImplementation "com.uandcode.flowtest:1.1.0"
// + default jetbrains library for testing coroutines if needed:
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2"

Simple usage example

Let's test the Flow.debounce() operator.

@Test
fun testDebouncedFlow() = runFlowTest { // <-- write runFlowTest instead of runTest
 val inputFlow = MutableSharedFlow<String>()
 val collector = inputFlow
 .debounce(100) // let's test how debounce works
 .startCollecting() // create test collector
 assertFalse(collector.hasItems) // assert no items at the beginning
 inputFlow.emit("item")
 advanceTimeBy(99) // wait 99 millis -> still no output
 assertFalse(collector.hasItems)
 advanceTimeBy(2) // wait a bit more, 101ms in total -> now the item should be emitted
 assertEquals("item", collector.lastItem)
 assertEquals(1, collector.count)
}

Usage example

Real-world scenario: here is a test verifying the repository.getCurrentUser() call returns a Flow with the current authorized user, even after executing other operations such as signIn() or logout().

@Test
fun testFlow() = runFlowTest { // <-- write runFlowTest instead of runTest
 val repository: UserRepository = createRepository()
 val currentUserFlow: Flow<User> = repository.getCurrentUser()
 val testFlowCollector: TestFlowCollector<User> = currentUserFlow.startCollecting()
 // assert the latest collected item
 assertEquals(User.ANONYMOUS, testFlowCollector.lastItem)
 // do something to make the flow to produce a new value
 repository.signIn("email", "password")
 // assert the latest collected item again
 assertEquals(User("email", "password"), testFlowCollector.lastItem)
 // example of other assertions:
 assertEquals(2, testFlowCollector.count)
 assertTrue(testFlowCollector.hasItems)
 assertEquals(
 listOf(User.ANONYMOUS, User("email", "password")),
 testFlowCollector.collectedItems,
 )
 assertEquals(CollectStatus.Collecting, testFlowCollector.collectStatus)
}

Troubleshooting

  1. If your code has delay() calls or other similar calls, use advanceTimeBy() in unit tests for managing virtual time.
  2. If your code uses CoroutineScope instances, do not forget to replace them in unit tests by TestScope or even backgroundScope (for infinite jobs/flows). For example, inject the test/background scope into the constructor when creating the object.
  3. Make sure you are using either UnconfinedTestDispatcher or StandardTestDispatcher instead of real dispatchers like Dispatchers.IO and so on. It is preferred to inject test dispatcher via class constructor.
  4. For testing android ViewModels, replace Dispatchers.Main by UnconfinedTestDispatcher or StandardTestDispatcher. You can set main dispatcher via Dispatchers.setMain(testDispatcher) and then reset it via Dispatchers.resetMain().

Documentation

Check out this link for more details.

About

A tiny library for easier testing of Kotlin Flows

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /