问题描述
我的源代码
open class RestaurantListviewmodel @Inject constructor(
private val restaurantApi: RestaurantApi
): viewmodel() {
private val _listofRestaurantsHolder = mutablelivedata<List<Restaurant>>()
private val _selectedRestaurant = mutablelivedata<Restaurant>()
/**
* Fetches all restaurants from a service call.
*/
fun fetchAllRestaurants()
{
viewmodelScope.launch {
fetchRestaurantsAsync()
_selectedRestaurant.value = null
}
}
/**
* Sets either the success response to the [_selectedRestaurant] live data or `null` in case of
* error response
*/
internal suspend fun fetchRestaurantsAsync() {
withContext(dispatchers.IO) {
restaurantApi.fetchRestaurantList().enqueue(object: Callback<List<Restaurant>> {
override fun onFailure(call: Call<List<Restaurant>>,t: Throwable) {
_listofRestaurantsHolder.value = null
}
override fun onResponse(
call: Call<List<Restaurant>>,response: Response<List<Restaurant>>
) {
_listofRestaurantsHolder.value = response.body()
}
})
}
}
}
测试
@ExperimentalCoroutinesApi
class RestaurantListviewmodelTest {
@get:Rule
val coroutinescope = MainCoroutinescopeRule()
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
@get:Rule
public val rule: MockitoRule = MockitoJUnit.rule()
lateinit var restaurantListviewmodel: RestaurantListviewmodel
@Mock
private lateinit var restaurantApi: RestaurantApi
@Before
fun setUp() {
restaurantListviewmodel = spy(RestaurantListviewmodel((restaurantApi)))
}
@Test
fun `test fetch all restaurants`() = runBlockingTest {
donothing().whenever(restaurantListviewmodel).fetchRestaurantsAsync()
restaurantListviewmodel.fetchAllRestaurants()
verify(restaurantListviewmodel).fetchRestaurantsAsync()
}
}
自定义协程范围:https://github.com/googlecodelabs/kotlin-coroutines/blob/master/coroutines-codelab/start/src/test/java/com/example/android/kotlincoroutines/main/utils/MainCoroutineScopeRule.kt
java.lang.IllegalStateException: This job has not completed yet
at kotlinx.coroutines.JobSupport.getCompletionExceptionorNull(JobSupport.kt:1189)
at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:53)
at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45)
at com.myproject.restaurant.viewmodels.RestaurantListviewmodelTest.test fetch all restaurants(RestaurantListviewmodelTest.kt:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.mockito.internal.junit.JUnitRule$1.evaluateSafely(JUnitRule.java:52)
at org.mockito.internal.junit.JUnitRule$1.evaluate(JUnitRule.java:43)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:61)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runchild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runchild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runchildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
disconnected from the target VM,address: '127.0.0.1:56527',transport: 'socket'
期望的行为
我希望能够在Kotlin中测试这两种方法。我会用Java完成以下操作。
donothing().whenever(restaurantListviewmodel).fetchRestaurantsAsync()
但是当我尝试用这种方式模拟一个暂停函数时,它会调用real方法,这不是我想要的。
当我如下更改测试方法时
@Test
fun `test fetch all restaurants`() = runBlocking {
donothing().whenever(restaurantListviewmodel).fetchRestaurantsAsync()
restaurantListviewmodel.fetchAllRestaurants()
verify(restaurantListviewmodel).fetchRestaurantsAsync()
}
java.lang.NullPointerException
at com.myproject.restaurant.RestaurantListviewmodel$fetchRestaurantsAsync$2.invokeSuspend(RestaurantListviewmodel.kt:41)
at |b|b|b(Coroutine boundary.|b(|b)
at com.krishnanand.doordash.viewmodels.RestaurantListviewmodelTest$test fetch all restaurants$1.invokeSuspend(RestaurantListviewmodelTest.kt:44)
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)