EnrollmentViewModelTest
@Test
fun getUserProfile() {
val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
val user = Gson().fromJson<User>(responseSnapshot, User::class.java)
val response = Response.success(user)
val deferred = CompletableDeferred<Response<User>>(response)
coEvery { userService.getUserDetail() } returns deferred
viewModel.getUserProfile()
assert(viewModel.loadingStatus.value != null)
assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false, viewModel.loadingStatus.value!!)
}
Вот EnrollmentViewModel.kt
fun getUserProfile() {
loadingStatus.postValue(true)
job = launch {
callAsync {
userService.getUserDetail()
}.onSuccess { user ->
if (user != null) {
processUserDetails(user)
}
loadingStatus.postValue(false)
}.onError {
//
}.onException {
//
}
}
}
Когда я отлаживаю тестовый пример, он показывает, что UITestUtil.getValue (viewModel.loadingStatus) !! ложно.
Но странно, контрольный пример не проходит, и когда я печатаю UITestUtil.getValue (viewModel.loadingStatus) !!. Это правда.
Это может быть связано с loadingStatus.postValue(true)
После того, как я удалю его, результат печати будет ложным.
Но я не знаю почему.
object UITestUtil {
/**
* Gets the value of a LiveData safely.
*/
@Throws(InterruptedException::class)
fun <T> getValue(liveData: LiveData<T>): T? {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
liveData.removeObserver(this)
}
}
liveData.observeForever(observer)
latch.await(2, TimeUnit.SECONDS)
return data
}
}
Обновлено:
import com.google.gson.Gson
import kotlinx.coroutines.Deferred
import retrofit2.Response
import retrofit2.Response.success
data class VPlusResult<T : Any?>(
val response: Response<T>? = null,
val exception: Exception? = null
)
inline fun <T : Any> VPlusResult<T>.onSuccess(action: (T?) -> Unit): VPlusResult<T> {
if (response?.isSuccessful == true)
action(response.body())
return this
}
inline fun <T : Any> VPlusResult<T>.onRawSuccess(action: (response: Response<T>) -> Unit): VPlusResult<T> {
if (response?.isSuccessful == true)
action(response)
return this
}
inline fun <T : Any, TR : Any> VPlusResult<T>.map(action: (T?) -> (TR)) =
if (response?.isSuccessful == true) VPlusResult(success(action(response.body())))
else this as VPlusResult<TR>
inline fun <T : Any> VPlusResult<T>.onError(action: (String) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
response?.errorBody()?.let {
action(it.string())
}
}
return this
}
inline fun <T : Any, reified G : Any> VPlusResult<T>.onErrorJson(action: (G) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
response?.errorBody()?.let {
action(Gson().fromJson(it.string(), G::class.java))
}
}
return this
}
inline fun <T : Any> VPlusResult<T>.onRawError(action: (Response<T>?) -> Unit): VPlusResult<T> {
if (response?.isSuccessful != true) {
action(response)
}
return this
}
inline fun <T : Any?> VPlusResult<T>.onException(action: (Exception) -> Unit) {
exception?.let { action(it) }
}
inline fun <T : Any> VPlusResult<T>.onSadness(action: (String?) -> Unit): VPlusResult<T> {
onError {
action(it)
}.onException {
action(it.message)
}
return this
}
suspend fun <T : Any> callAsync(block: () -> Deferred<Response<T>>): VPlusResult<T> {
return try {
VPlusResult(block().await())
} catch (e: Exception) {
VPlusResult(exception = e)
}
}
Обновлено 2:
добавление любого из следующих операторов до того, как оператор assert получитзначение false, которое проходит тестовый пример.
coVerify { userService.getUserDetail() }
coVerify { viewModel.processUserDetails(user) }
Обновление 3: fun loadAllTasksFromRepository_loadingTogglesAndDataLoaded () в https://github.com/android/architecture-samples Также работает, но я пытаюсь ввести в свои кодытоже не получилось.
@ExperimentalCoroutinesApi
@Test
fun getUserProfile4Using() {
// using TestCoroutineScope in kotlinx.coroutines.test
// Pause dispatcher so we can verify initial values
mainCoroutineRule.pauseDispatcher()
val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
val user = Gson().fromJson<User>(responseSnapshot, User::class.java)
val response = Response.success(user)
val deferred = CompletableDeferred<Response<User>>(response)
// coEvery { userService.getUserDetail() } returns deferred
viewModel.getUserProfile()
assert(viewModel.loadingStatus.value != null)
// verify { viewModel.processUserDetails(user) }
print(viewModel.loadingStatus.value)
assert(UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(true, viewModel.loadingStatus.value!!)
// Execute pending coroutines actions
mainCoroutineRule.resumeDispatcher()
print(viewModel.loadingStatus.value!!)
assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false, viewModel.loadingStatus.value!!)
}