android - Kotlin Coroutines ViewModel Unit Testing with Mockito using Retrofit MVVM throws Null pointer Exception
问题描述
我尝试对使用 Kotlin 协程进行改造 API 调用的 ViewModel 进行单元测试。单元测试失败,出现空指针异常。
当使用 Retrofit RXJAva UnitTest Passes 进行相同尝试时。使用 Mockito 框架。
请检查我的代码并让我知道我的代码中出现的错误。
请在下面找到 ViewModel 和 UnitTest 类文件:
fetchResponseFromAPI()方法进行 API 调用以获取数据
RetroCoroutineViewModel.kt:
class RetroCoroutineViewModel : ViewModel(),LifecycleObserver{
private val errorOnAPI = MutableLiveData<String>()
private val mutableLiveData:MutableLiveData<List<RetroRxModel>> = MutableLiveData()
var loading : MutableLiveData<Boolean> = MutableLiveData()
@Inject
lateinit var retrofit: Retrofit
lateinit var apiService: APIService
init {
DaggerRetroRxComponent.create().inject(this)
loading.value = true
apiService = retrofit.create(APIService::class.java)
}
val postsMutableLiveData:MutableLiveData<List<RetroRxModel>> = MutableLiveData()
**@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun fetchResponseFromAPI(){**
viewModelScope.launch {
try{
val response = apiService.fetchUserPosts()
if(response.isSuccessful){
postsMutableLiveData.postValue(response.body())
loading.value = false
}else{
loading.value = false
errorOnAPI.postValue("Something went wrong::${response.message()}")
}
}catch (e:Exception){
loading.value = false
errorOnAPI.postValue("Something went wrong::${e.localizedMessage}")
}
}
}
fun fetchPostLiveData(): LiveData<List<RetroRxModel>> = postsMutableLiveData
override fun onCleared() {
super.onCleared()
}
fun fetchError(): LiveData<String> = errorOnAPI
fun fetchLoadStatus():LiveData<Boolean> = loading
private fun onError(message: String){
errorOnAPI.value = message
loading.value = false
}
}
RetroCoroutineViewModelTest:
@RunWith(MockitoJUnitRunner::class)
@ExperimentalCoroutinesApi
class RetroCoroutineViewModelTest {
@get:Rule
val testInstantTaskExecutorRule: TestRule = InstantTaskExecutorRule()
@get:Rule
val testCoroutineRule = TestCoroutineRule()
@Mock
lateinit var retrofit: Retrofit
@Mock
lateinit var apiService: APIService
lateinit var retroCoroutineViewModel: RetroCoroutineViewModel
private lateinit var response: Response<List<RetroRxModel>>
private var loading: Boolean = false
@Before
fun setUp(){
MockitoAnnotations.initMocks(this)
}
@Test
fun fetchRetroInfoTest_success(){
retroCoroutineViewModel = RetroCoroutineViewModel()
testCoroutineRule.runBlockingTest {
var retroRxModel = RetroRxModel("tile", "body", "1")
var retroRXModelList = ArrayList<RetroRxModel>()
retroRXModelList.add(retroRxModel)
response = Response.success(retroRXModelList)
if (retrofit != null) {
if (apiService != null) {
Mockito.`when`(apiService.fetchUserPosts()).thenReturn(response)
retroCoroutineViewModel.fetchResponseFromAPI()
}
}
val funResponse = retroCoroutineViewModel.fetchPostLiveData()
println("Response::::${funResponse.value}")
Assert.assertEquals(1,funResponse.value?.size)
Assert.assertEquals(loading,retroCoroutineViewModel.loading)
}
}
}
当我尝试运行单元测试用例时,我观察到以下异常:
java.lang.AssertionError:预期:1 实际:null
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.rxretrofit.RetroCoroutineViewModelTest$fetchRetroInfoTest_success$1.invokeSuspend(RetroCoroutineViewModelTest.kt:75)
构建.Gradle:
testImplementation "org.mockito:mockito-core:3.3.3"
testImplementation 'androidx.arch.core:core-testing:2.1.0'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.4'
解决方案
推荐阅读
- php - 如何对另一个wordpress php文件进行href?
- reactjs - React + Redux + Storybook:在编写故事书故事时如何使用连接的 React 路由器的 useParams?
- scala - 在 IntelliJ 中使用 Gradle 构建具有依赖项的 Jar,包括多个主类
- spring-data-jpa - 如何转换为 JPQL 用于内联视图?
- c++ - 仅当我们在优先级队列中使用自定义比较器时才需要传递容器类型?
- javascript - 根据重复出现修改数组值
- ios - 我可以使用 NavigationController 来解除屏幕移动吗?
- php - 如何在 PHP 标记 echo 内的脚本中使用 jquery 变量?
- javascript - 在 Django 中弹出消息
- react-native - React Native 是否支持 Apple 的 M1 macbook pro?