I'm trying to test a `ViewModel` whereby it contai...
# android
p
I'm trying to test a
ViewModel
whereby it contains a function that calls another suspending function of a library, then assign its return value to an internal state. I want to uni test this function, but unit tests end before the inner suspending function returns.
Copy code
class FloatingBubbleViewModel(
    private val application: Application = Application(),
    private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.Default
) : AndroidViewModel(application) {
    fun translateWord() = 
        viewModelScope.launch(coroutineDispatcher) { // Doesn't work
        // runBlocking {                                // Works during testing
            targetWordDisplay = Translator().translate(
                text = srcWordDisplay,
                source = Language.AUTO,
                target = Language.ENGLISH
            ).translatedText
        }
}
during unit testing, I've modified the dispatcher, but to no avail. It only works when the original code is invoked using
runBlocking
rather than
ViewModeScope
(even after injecting a custom dispatcher)
Copy code
class TranslationTest {

    @ExperimentalCoroutinesApi
    @get:Rule
    val mainCoroutineRule = MainCoroutineRule()

    @OptIn(ExperimentalCoroutinesApi::class)
    private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()

    private lateinit var floatingBubbleViewModel: FloatingBubbleViewModel

    @Before
    fun setup() {
        floatingBubbleViewModel = FloatingBubbleViewModel()
    }

    @OptIn(ExperimentalCoroutinesApi::class)
    @Test
    fun translateWordTest(): Unit = runTest {
            val word = "eingaben"
            floatingBubbleViewModel.srcWordDisplay = word
            floatingBubbleViewModel.translateWord() // Doesn't work
            // floatingBubbleViewModel.translateWord().join() // Works
            advanceUntilIdle()
            println(floatingBubbleViewModel.targetWordDisplay}) // Returns empty string.
    }

}

@OptIn(ExperimentalCoroutinesApi::class)
class MainCoroutineRule(
    private val dispatcher: TestDispatcher = StandardTestDispatcher()
): TestWatcher() {
    override fun starting(description: Description?) {
        super.starting(description)
        Dispatchers.setMain(dispatcher)
    }
    override fun finished(description: Description?) {
        super.finished(description)
        Dispatchers.resetMain()
    }
}