协程:覆盖 OKHttp 的调度程序以使用 AsyncTasks 的 ThreadPoolExecutor,以便 Espresso 可以成功断言
Coroutines: Overriding OKHttp's dispatcher to use AsyncTasks's ThreadPoolExecutor so Espresso can assert successfully
我正在迁移一个使用 Retrofit
来处理协程的应用程序。该应用程序有一些失败的 UAT,因为 Espresso 不等待协程完成并立即断言。
CoroutineCallAdapterFactory
默认使用OkHttp的Dispatcher
进行异步请求,但是Espresso
只监听UIThread
和[=16] =] 的 Thread
池。我想到的一种解决方案是强制 OkHttp
的 Dispatcher 使用 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()
}
我正在迁移一个使用 Retrofit
来处理协程的应用程序。该应用程序有一些失败的 UAT,因为 Espresso 不等待协程完成并立即断言。
CoroutineCallAdapterFactory
默认使用OkHttp的Dispatcher
进行异步请求,但是Espresso
只监听UIThread
和[=16] =] 的 Thread
池。我想到的一种解决方案是强制 OkHttp
的 Dispatcher 使用 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()
}