单元测试未提供预期结果

问题描述 投票:0回答:1

MainViewModelTest.kt 中的我的单元测试无法正常工作。似乎行 _recentTvShowList.update {licateRemoverSet.toList() } 没有更新。我已经模拟了存储库和 dao,所以我无法弄清楚为什么它不起作用。

MainViewModelTest.kt

@ExperimentalCoroutinesApi
class MainViewModelTest {
    private lateinit var repository: TvShowsRepository
    private lateinit var dao: TvShowCheckerDao
    private val viewModel: MainViewModel by lazy { MainViewModel(repository) }

    @ExperimentalCoroutinesApi
    @get:Rule
    val mainDispatcherRule = MainDispatcherRule()

    private val testModules = module {
        single<TvShowsRepository> { mockk<TvShowsRepository>() }
        viewModel { MainViewModel(get()) }
    }

    @ExperimentalCoroutinesApi
    class MainDispatcherRule(private val dispatcher: TestDispatcher = StandardTestDispatcher()) :
        TestWatcher() {
        override fun starting(description: Description?) = Dispatchers.setMain(dispatcher)

        override fun finished(description: Description?) = Dispatchers.resetMain()

    }

    @Before
    fun setUp() {
        repository = mockk(relaxed = true)
        dao = mockk(relaxed = true)
        startKoin { modules(testModules) }
    }

    @After
    fun tearDown() {
        stopKoin()
    }

    @ExperimentalCoroutinesApi
    @Test
    fun `tests getRecentTvShows() returns list of recent tv shows`() = runTest {
        val repository: TvShowsRepository = mockk()
        val tvShow1 = TvShow(
            id = 1,
            description = "Show 1",
            title = "Description 1",
            airDate = "https://example.com/show1.jpg"
        )
        val tvShow2 = TvShow(
            id = 2,
            description = "Show 2",
            title = "Description 2",
            airDate = "https://example.com/show2.jpg"
        )
        coEvery { dao.getRecentTvShows() } returns listOf(tvShow1, tvShow2)
        coEvery { repository.getRecentTvShows() } returns flowOf(listOf(tvShow1, tvShow2))
        viewModel.getRecentTvShows()

        val expectedList = listOf(tvShow1, tvShow2)
        viewModel.recentTvShowList.test {
            assertEquals(expectedList, awaitItem())
        }
    }
}

在 MainViewModel.kt 中测试功能

suspend fun getRecentTvShows() {
        val duplicateRemoverSet = mutableSetOf<TvShow>()
        repository.getRecentTvShows().collect { tvShowList ->
            tvShowList.forEach {
                duplicateRemoverSet.add(it)
            }
        }

        _recentTvShowList.update { duplicateRemoverSet.toList() }
    }

完整的MainViewModel.kt

@OptIn(FlowPreview::class)
class MainViewModel(
    private val repository: TvShowsRepository
) : ViewModel() {
    private val _searchText = MutableStateFlow("")
    val searchText = _searchText.asStateFlow()

    private val _isSearching = MutableStateFlow(false)
    val isSearching = _isSearching
        .onStart { getTvShows() }
        .stateIn(
            viewModelScope,
            SharingStarted.WhileSubscribed(5000),
            false
        )

    private val _isLoading = MutableStateFlow(false)
    val isLoading = _isLoading.asStateFlow()

    private val _isEpisodesLoading = MutableStateFlow(false)
    val isEpisodesLoading = _isEpisodesLoading.asStateFlow()

    private val _selectedTvShow = MutableStateFlow<TvShowExtended?>(null)
    val selectedTvShow = _selectedTvShow.asStateFlow()

    private val _selectedSeason = MutableStateFlow(listOf<TvShowSeasonEpisodes>())
    val selectedSeason = _selectedSeason.asStateFlow()

    private val _error = MutableStateFlow("")
    val error = _error.asStateFlow()

    private val _tvShowList = MutableStateFlow(listOf<TvShow>())
    val tvShowList = searchText
        .debounce(1_000L)
        .onEach { _isSearching.update { true } }
        .combine(_tvShowList) { text, tvShow ->
            if (text.isBlank()) {
                tvShow
            } else {
                tvShow.filter { it.searchTvShow(text) }
            }
        }.onEach { _isSearching.update { false } }
        .stateIn(
            viewModelScope,
            SharingStarted.WhileSubscribed(5000),
            _tvShowList.value
        )

    private val _recentTvShowList = MutableStateFlow(listOf<TvShow>())
    val recentTvShowList = _recentTvShowList.asStateFlow()

//    init {
//        viewModelScope.launch {
//            getRecentTvShows()
//        }
//    }

    fun onSearchTextChange(text: String) {
        _searchText.value = text
        viewModelScope.launch { getTvShows(text) }
    }

    private suspend fun getTvShows(query: String = ""): List<TvShow> {
        val duplicateRemoverSet = mutableSetOf<Result>()
        try {
            val temp = repository.getTVShows(query).results
            temp.forEach {
                duplicateRemoverSet.add(it)
            }
        } catch (e: Exception) {
            _error.update { e.localizedMessage ?: "No error found" }
        }
        val tvShowList = AppMapper.mapGetTvShowsApiResultToTvShowList(duplicateRemoverSet.toList())
        _tvShowList.update { tvShowList }
        return tvShowList
    }

    suspend fun getRecentTvShows() {
        val duplicateRemoverSet = mutableSetOf<TvShow>()
        repository.getRecentTvShows().collect { tvShowList ->
            tvShowList.forEach {
                duplicateRemoverSet.add(it)
            }
        }

        _recentTvShowList.update { duplicateRemoverSet.toList() }
    }

    fun insertRecentTvShow(tvShow: TvShow) {
        viewModelScope.launch {
            repository.insertRecentTvShow(tvShow = tvShow)
        }
    }

    fun getTvShowById(tvShowId: Int) {
        viewModelScope.launch {
            try {
                _searchText.update { "" }
                val apiResult = repository.getTVShowById(tvShowId)
                val result = AppMapper.mapGetTvShowByIdApiResultToTvShow(apiResult)
                _selectedTvShow.update { result }
            } catch (e: Exception) {
                _error.update { e.localizedMessage ?: "No error found" }
            }
        }
    }

    fun getTvShowSeasons(tvShowId: Int, seasonNumber: Int = 1) {
        viewModelScope.launch {
            _isEpisodesLoading.value = true
            try {
                val apiResult = repository.getTvShowSeason(tvShowId, seasonNumber)
                val result = AppMapper.mapGetTvShowSeasonsApiResultToTvShowSeason(apiResult)
                result.forEach {
                    it.isChecked = repository.getIsWatchedStatus(it.episodeId)
                    it.tvShowId = tvShowId
                    insertTvShowSeasonEpisodesToDB(it)
                }
                _selectedSeason.update { result }
            } catch (e: Exception) {
                _error.update { e.localizedMessage ?: "No error found" }
            }
            _isEpisodesLoading.value = false
        }
    }

    fun getTvShowSeasonsOffline(tvShowId: Int, seasonSelected: Int) {
        viewModelScope.launch {
            _isEpisodesLoading.value = true
            try {
                val databaseResult = repository.getTvShowSeasonOffline(tvShowId, seasonSelected)
                _selectedSeason.update { databaseResult }
            } catch (e: Exception) {
                _error.update { e.localizedMessage ?: "No error found" }
            }
            _isEpisodesLoading.value = false
        }
    }

    private fun insertTvShowSeasonEpisodesToDB(tvShowSeasonEpisodes: TvShowSeasonEpisodes) {
        viewModelScope.launch {
            repository.insertTvShow(tvShowSeasonEpisodes)
        }
    }

    fun updateIsWatchedState(episodeId: Int, isWatched: Boolean) {
        viewModelScope.launch {
            repository.updateIsWatchedStatus(episodeId = episodeId, isWatchedStatus = isWatched)
        }
    }
}
android kotlin junit mockk
1个回答
0
投票

awaitItem()
将返回流中第一个发出的值。您可以尝试使用
expectMostRecentItem()
来获取最新的发射值吗?

viewModel.recentTvShowList.test {
     assertEquals(expectedList, expectMostRecentItem())
}
© www.soinside.com 2019 - 2024. All rights reserved.