Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

167
Views
How do I test a viewModelScope controlled SharedFlow?

I have a SharedFlow. When the ViewModel is created, I change the value to Val1. After that, I use the viewModelScope to make some fake delay of 3 seconds and then change the value to Val2.

class MyViewModel : ViewModel() {

    val x = MutableSharedFlow<String>()

    init {
        x.tryEmit("Val1")
        viewModelScope.launch {
            delay(3000)
            x.tryEmit("Val2")
        }
    }
}

Question

  1. How do I test the initial value is Val1?
  2. How do I test if the value has changed to Val2 after delay?
over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

I found the solution:

It's as simple as setting the Main dispatcher to TestCoroutineDispatcher.

@ExperimentalCoroutinesApi
class CoroutineMainExtension : BeforeEachCallback, AfterEachCallback {
    val dispatcher = TestCoroutineDispatcher()
    override fun beforeEach(context: ExtensionContext?) {
        Dispatchers.setMain(dispatcher)
    }

    override fun afterEach(context: ExtensionContext?) {
        Dispatchers.resetMain()
        dispatcher.cleanupTestCoroutines()
    }
}

and use it like this:

@ExtendWith(CoroutineMainExtension::class)

over 4 years ago · Santiago Trujillo Report

0

To test it, you need a way to inject your testing context. It is typically done by setting it as Dispatchers.Main.

Then the easy path is to use MutableStateFlow instead of MutableSharedFlow. Here is an example:

class MyViewModel : ViewModel() {

    val x = MutableStateFlow("Val1")

    init {
        viewModelScope.launch {
            delay(3000)
            x.tryEmit("Val2")
        }
    }
}

class MyViewModelTests {
    private val testDispatcher = TestCoroutineDispatcher()

    @Before
    fun setUp() {
        Dispatchers.setMain(testDispatcher)
    }

    @Test
    fun test() = runBlocking {
        // given
        val myViewModel = MyViewModel()

        // then
        assertEquals("Val1", myViewModel.x.value)

        // when
        testDispatcher.advanceTimeBy(3000)

        // then
        assertEquals("Val2", myViewModel.x.value)
    }
}

If you want to test MutableSharedFlow, you should better move your logic from the constructor to some function, like onCreate. Then you should collect and observe how your values change. Here is an example (we could make a better one with some testing library like Turbine):

class MyViewModel : ViewModel() {

    val x = MutableSharedFlow<String>()

     fun onCreate() {
        viewModelScope.launch {
            x.emit("Val1")
            delay(3000)
            x.emit("Val2")
        }
    }
}

class MyViewModelTests {
    private val testDispatcher = TestCoroutineDispatcher()

    @Before
    fun setUp() {
        Dispatchers.setMain(testDispatcher)
    }

    @Test
    fun test() = runBlocking {
        // given
        val myViewModel = MyViewModel()
        var xChangeHistory = mapOf<Long, String>()
        myViewModel.viewModelScope.launch {
            myViewModel.x.collect {
                xChangeHistory += testDispatcher.currentTime to it
            }
        }

        // then
        myViewModel.onCreate()
        testDispatcher.advanceUntilIdle()

        // then
        assertEquals(mapOf(0L to "Val1", 3000L to "Val2"), xChangeHistory)
    }
}
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!