我正在try 为我的应用程序编写单元测试.我正在使用Mockk来模拟课堂.
这是我的单元测试
@OptIn(ExperimentalCoroutinesApi::class)
class MainViewModalTest {
private lateinit var viewModel: MainViewModal
private val savedStateHandle = mockk<SavedStateHandle>(relaxed = true)
private val randomFactUseCase = mockk<RandomFactUseCase>()
@get:Rule
val mainDispatcher = MainDispatcherRule()
@Before
fun setup() {
viewModel = MainViewModal(randomFactUseCase, savedStateHandle)
}
@Test
fun `When fetchRandomFact succeeds, update UI state with fact`() = runBlockingTest {
// Given
coEvery { randomFactUseCase.invoke() } returns Result.Success(RandomFact(data = listOf("Some interesting fact")), 200)
// When
viewModel.fetchRandomFact()
// Then
val expectedUiState = UiState(loading = false, fact = "Some interesting fact", error = "")
assert(viewModel.uiState.value == expectedUiState)
}
}
class MainDispatcherRule(private val testDispatcher: TestDispatcher = UnconfinedTestDispatcher()) :
TestWatcher() {
override fun starting(description: Description) {
super.starting(description)
Dispatchers.setMain(testDispatcher)
}
override fun finished(description: Description) {
super.finished(description)
Dispatchers.resetMain()
}
}
它失败,并出现此错误
线程"Test Worker@Coroutine#1"中出现异常 Io.moockk.MockKException:找不到以下项的答案 RandomFactUseCase(#2).Invoke(继续{})在配置的 答案:()
这是我的viewModel:
@HiltViewModel
class MainViewModal @Inject constructor(
private val randomFactUseCase: RandomFactUseCase,
private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
init {
fetchRandomFact()
}
val uiState: StateFlow<UiState> = savedStateHandle.getStateFlow("fact", UiState(loading = true))
fun fetchRandomFact() {
viewModelScope.launch {
setState(loading = true)
when (val response = randomFactUseCase()) {
is Result.Success -> {
val fact =
if (response.data?.data?.isNotEmpty() == true) response.data.data[0] else ""
setState(
loading = false,
fact = fact,
error = if (fact.isBlank()) "No fact available!" else ""
)
}
is Result.Error -> {
setState(
loading = false,
fact = "",
error = response.exception.message
?: "Something went wrong! Please try again"
)
}
}
}
}
private fun setState(loading: Boolean = true, fact: String = "", error: String = "") {
savedStateHandle["fact"] = UiState(loading = loading, fact = fact, error = error)
}
}
@Parcelize
data class UiState(val loading: Boolean = true, val fact: String = "", val error: String = "") :
Parcelable
不知道我在这里错过了什么.虽然我觉得我已经很接近了.
EDIT1: 根据@broots的建议,我已经按如下方式更新了viewModel:
@HiltViewModel
class MainViewModal @Inject constructor(
private val randomFactUseCase: RandomFactUseCase,
private val savedStateHandle: SavedStateHandle,
) : ViewModel() {
init {
invokeFunction()
}
fun invokeFunction() {
viewModelScope.launch {
fetchRandomFact()
}
}
val uiState: StateFlow<UiState> = savedStateHandle.getStateFlow("fact", UiState(loading = true))
suspend fun fetchRandomFact() {
setState(loading = true)
when (val response = randomFactUseCase()) {
is Result.Success -> {
val fact =
if (response.data?.data?.isNotEmpty() == true) response.data.data[0] else ""
setState(
loading = false,
fact = fact,
error = if (fact.isBlank()) "No fact available!" else ""
)
}
is Result.Error -> {
setState(
loading = false,
fact = "",
error = response.exception.message ?: "Something went wrong! Please try again"
)
}
}
}
private fun setState(loading: Boolean = true, fact: String = "", error: String = "") {
savedStateHandle["fact"] = UiState(loading = loading, fact = fact, error = error)
}
}
这并没有解决问题.(新增此内容以供参考)