How to inject viewModelScope for Android unit test with Kotlin coroutines?

前端 未结 1 1143
暖寄归人
暖寄归人 2021-01-06 09:45

Questions

  1. What is the best strategy to inject viewModelScope for Android unit tests with Kotlin coroutines?

  2. When the Coroutin

1条回答
  •  抹茶落季
    2021-01-06 09:58

    Inject and determine CoroutineScope on ViewModel creation

    In production, the ViewModel is created with a null coroutineScopeProvider, as the ViewModel's viewModelScope is used. For testing, TestCoroutineScope is passed as the ViewModel argument.

    SomeUtils.kt

    /**
     * Configure CoroutineScope injection for production and testing.
     *
     * @receiver ViewModel provides viewModelScope for production
     * @param coroutineScope null for production, injects TestCoroutineScope for unit tests
     * @return CoroutineScope to launch coroutines on
     */
    fun ViewModel.getViewModelScope(coroutineScope: CoroutineScope?) =
        if (coroutineScope == null) this.viewModelScope
        else coroutineScope
    

    SomeViewModel.kt

    class FeedViewModel(
        private val coroutineScopeProvider: CoroutineScope? = null,
        private val repository: FeedRepository
    ) : ViewModel() {
    
        private val coroutineScope = getViewModelScope(coroutineScopeProvider)
    
        fun getSomeData() {
            repository.getSomeDataRequest().onEach {
                // Some code here.            
            }.launchIn(coroutineScope)
        }
    
    }
    

    SomeTest.kt

    @ExperimentalCoroutinesApi
    class FeedTest : BeforeAllCallback, AfterAllCallback {
    
        private val testDispatcher = TestCoroutineDispatcher()
        private val testScope = TestCoroutineScope(testDispatcher)
        private val repository = mockkClass(FeedRepository::class)
        private var loadNetworkIntent = MutableStateFlow(null)
    
        override fun beforeAll(context: ExtensionContext?) {
            // Set Coroutine Dispatcher.
            Dispatchers.setMain(testDispatcher)
        }
    
        override fun afterAll(context: ExtensionContext?) {
            Dispatchers.resetMain()
            // Reset Coroutine Dispatcher and Scope.
            testDispatcher.cleanupTestCoroutines()
            testScope.cleanupTestCoroutines()
        }
    
        @Test
        fun topCafesPoc() = testDispatcher.runBlockingTest {
            ...
            val viewModel = FeedViewModel(testScope, repository)
            viewmodel.getSomeData()
            ...
        }
    }
    

    0 讨论(0)
提交回复
热议问题