Я переношу приложение, которое использует Retrofit
для работы с сопрограммами. В приложении есть некоторые UAT, которые дают сбой, потому что Espresso не ждет завершения сопрограмм и немедленно утверждает.
CoroutineCallAdapterFactory
по умолчанию использует Dispatcher
OkHttp для выполнения асинхронных запросов, но Espresso
отслеживает только пользовательский интерфейс Thread
и пул AsyncTaks
Thread
. Одно из решений, о котором я подумал, — заставить Диспетчер OkHttp
использовать AsyncTask
ThreadPoolExecutor
.
val dispatcher = Dispatcher(AsyncTask.THREAD_POOL_EXECUTOR as ExecutorService)
okHttpClientBuilder.dispatcher(dispatcher)
Кажется, это работает, и тесты проходят.
Это плохая идея? Является ли регистрация IdlingResource
лучшим вариантом?
Без дополнительных подробностей о вашей настройке я не уверен, поможет ли эта информация, но я упомяну несколько советов, которые могут помочь с вашими тестами:
Вы также можете пойти другим путем и создать диспетчер сопрограмм из любого исполнителя, используя:
AsyncTask.THREAD_POOL_EXECUTOR.asCoroutineDispatcher()
И, конечно же, это можно использовать в любом месте, где у вас будет что-то вроде Dispatchers.Main
, что означает, что вы можете создать область из этого и запустить свои сопрограммы из этой области, и Espresso должен отслеживать базовый пул исполнителей для завершения. Например:
...
val espressoScope = CoroutineScope(AsyncTask.THREAD_POOL_EXECUTOR.asCoroutineDispatcher())
...
espressoScope.launch { api.getBooks() }
Точно так же вы можете делать такие вещи, как:
val asyncTaskContext = AsyncTask.THREAD_POOL_EXECUTOR.asCoroutineDispatcher()
withContext(asyncTaskContext) {
api.getBooks()
}
// OR:
@Test
fun someAndroidTest() = runBlocking(asyncTaskContext) {
// espresso logic
}
И последнее, но не менее важное: вы можете присоединяться к любым заданиям, которые вы создаете в своем тесте, и тест будет ждать завершения задания перед выходом. Это похоже на подход, который больше всего поможет в вашей ситуации, поскольку вы действительно просто хотите дождаться завершения сопрограмм:
@Test
fun `first book has a title`() = runBlocking {
launch {
// run a function that suspends and takes a while
val firstBook = api.getAllBooks().first()
assertNotNull(firstBook.title)
}.join()
}
Я думал, что AsyncTask
API устарел Google?
Так можно ли использовать пул потоков AsyncTask? Я знаю, что диспетчеры сопрограмм оптимизированы для выполнения поставленной задачи (т. е. Dispatcher.IO оптимизирован для задач ввода-вывода), и я не знаю, оптимизирован ли пул потоков AsyncTask.