Создание ресурса CoroutineDispatcher IdlingResource для эспрессо-тестов - PullRequest
1 голос
/ 13 июня 2019

Я пытаюсь найти способ красиво реализовать IdlingResource, который будет опрашивать свойство CoroutineDispatcher isActive. Однако из-за отладки при проверке этого свойства никогда не появляется активное задание.

До сих пор я пытался использовать THREAD_POOL_EXECUTOR от AsyncTask для встроенного холостого хода, но, похоже, он не работает при использовании функции расширения asCoroutineDispatcher и использовании этого результата CoroutineDispatcher для запуска задания ViewModel. Я попытался написать собственный IdlingResource

ViewModel

fun authenticate(username: String, password: String) = viewModelScope.launch(Dispatchers.Default) {
    if (_authenticateRequest.value == true) {
        return@launch
    }

    _authenticateRequest.postValue(true)
    val res = loginRepo.authenticate(username, password)
    _authenticateRequest.postValue(false)

    when {
        res is Result.Success -> {
            _authenticateSuccess.postValue(res.item)
        }
        res is Result.Failure && res.statusCode.isHttpClientError -> {

            _authenticateFailure.postValue(R.string.invalid_password)
        }
        else -> {
            _authenticateFailure.postValue(R.string.network_error)
        }
    }
}

IdlingResource

class CoroutineDispatcherIdlingResource(
    private val resourceName: String,
    private val dispatcher: CoroutineDispatcher
) : IdlingResource {
    private var callback: IdlingResource.ResourceCallback? = null

    override fun getName() = resourceName

    override fun isIdleNow(): Boolean {
        if (dispatcher.isActive) { return false }

        callback?.onTransitionToIdle()
        return true
    }

    override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) {
        this.callback = callback
    }
}

Эспрессо-тест

@RunWith(AndroidJUnit4::class)
class LoginIntegrationTest {
    @get:Rule
    val activityRule = ActivityTestRule(MainActivity::class.java)

    var idlingResource: CoroutineDispatcherIdlingResource? = null

    @Before
    fun before() {
        idlingResource = CoroutineDispatcherIdlingResource(this.javaClass.simpleName, Dispatchers.Default)
        IdlingRegistry.getInstance().register(idlingResource)
    }

    @Test
    fun loginFailure() {
        onView(withId(R.id.username))
            .perform(clearText()).perform(typeText("aslkdjqwe"))
        onView(withId(R.id.password))
            .perform(clearText()).perform(typeText("oxicjqwel"))
        onView(withId(R.id.login_button))
            .perform(click())

        onView(withId(com.google.android.material.R.id.snackbar_text))
            .check(matches(withText(R.string.invalid_password)))
    }
}

Я ожидаю, что свойство isActive станет истинным после вызова функции authenticate ViewModel, но, похоже, это не так. Это всегда выглядит как ложь, так как в CoroutineDispatcher никогда не бывает активного задания.

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

Разобрался с решением!Оказывается, что THREAD_POOL_EXECUTOR в AsyncTask действительно работал нормально для этого.Чего мне не хватало, так это наличия IdlingResource для Retrofit / OkHttp.

Мое первоначальное предположение заключалось в том, что сопрограмма, работающая на THREAD_POOL_EXECUTOR, будет неявно ожидать, пока клиент HTTP отключается, но я использовал IdlingResource здесь чтобы все было хорошо.

0 голосов
/ 13 июня 2019

CoroutineContext.isActive вводит в заблуждение, поскольку он проверяет, имеет ли контекст объект Job и является ли он активным.CoroutineDispatcher - это контекст без других элементов, таких как Job, поэтому он всегда будет возвращать false.

. Чтобы отслеживать продолжения, вам, вероятно, понадобится какой-то пользовательский ContinuationInterceptor, который отслеживает незавершенные и отмененные продолжения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...