I have search view model like this.
searchPoiUseCase
doing requests to Room DB. For testing purposes i am using Room.inMemoryDatabaseBuilder
.
@HiltViewModel
class SearchVm @Inject constructor(
private val searchPoiUseCase: SearchPoiUseCase
) : ViewModel() {
private val queryState = MutableStateFlow("")
@OptIn(FlowPreview::class)
val searchScreenState = queryState
.filter { it.isNotEmpty() }
.debounce(500)
.distinctUntilChanged()
.map { query -> searchPoiUseCase(SearchPoiUseCase.Params(query)) }
.map { result ->
if (result.isEmpty()) SearchScreenUiState.NothingFound
else SearchScreenUiState.SearchResult(result.map { it.toListUiModel() })
}
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(5_000),
SearchScreenUiState.None
)
fun onSearch(query: String) {
queryState.value = query
}
}
On the device this logic works perfectly fine. But i can't succeed with Unit Testing this logic. Here is my unit test:
@OptIn(ExperimentalCoroutinesApi::class)
@HiltAndroidTest
@Config(application = HiltTestApplication::class)
@RunWith(RobolectricTestRunner::class)
class SearchViewModelTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
@Inject
lateinit var searchUseCase: SearchPoiUseCase
lateinit var SUT: SearchVm
@Before
fun setup() {
hiltRule.inject()
SUT = SearchVm(searchUseCase)
Dispatchers.setMain(UnconfinedTestDispatcher())
}
@After
fun teardown() {
Dispatchers.resetMain()
}
@Test
fun `test search view model`() = runTest {
val collectJob = launch { SUT.searchScreenState.collect() }
assertEquals(SearchScreenUiState.None, SUT.searchScreenState.value)
SUT.onSearch("Query")
assertEquals(SearchScreenUiState.NothingFound, SUT.searchScreenState.value)
collectJob.cancel()
}
}
The second assertion always failed. Am i missing something? Thanks in advance!
UPDATED Thanks to Ibrahim Disouki
His solution working for me with one change
@Test
fun `test search view model`() = runTest {
whenever(searchUseCase(SearchPoiUseCase.Params("Query"))).thenReturn(emptyList()) // here you can create another test case when return valid data
assertEquals(SearchScreenUiState.None, SUT.searchScreenState.value)
val job = launch {
SUT.searchScreenState.collect() //now it should work
}
SUT.onSearch("Query")
advanceTimeBy(500) // This is required in order to bypass debounce(500)
runCurrent() // Run any pending tasks at the current virtual time, according to the testScheduler.
assertEquals(SearchScreenUiState.NothingFound, SUT.searchScreenState.value)
job.cancel()
}