我正在编写在 UI 中执行操作的集成测试,这些操作使用Retrofit启动网络调用。
我知道我需要实现 a CountingIdlingResource
,但我想以正确的方式来做(如果已经完成,不要重新发明轮子)。
是否有人IdlingResource
在其应用程序的Espresso测试套件中实现了等待网络请求执行的功能?
更多信息在这里。
我正在编写在 UI 中执行操作的集成测试,这些操作使用Retrofit启动网络调用。
我知道我需要实现 a CountingIdlingResource
,但我想以正确的方式来做(如果已经完成,不要重新发明轮子)。
是否有人IdlingResource
在其应用程序的Espresso测试套件中实现了等待网络请求执行的功能?
更多信息在这里。
最直接的解决方案是:基本上用 AsyncTask 替换 Retrofit 的线程池执行器(正如链接的 Google 小组讨论中非常有帮助的 Nick 所推荐的那样)。我这样做是这样的:
new RestAdapter.Builder()
.setEndpoint(LOCLSET_SERVER_URL)
.setExecutors(AsyncTask.THREAD_POOL_EXECUTOR,
new MainThreadExecutor())
.build();
我不确定这是否是最合适的解决方案,但它是我可以开始工作的最快最理智的解决方案。请记住,这仅适用于 ICS+。
如果你在 Retrofit 2.0 中使用 RxJava Observables,那么你可以使用.subscribeOn(Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR))
代替,.subscribeOn(Schedulers.io())
一切正常!
或者,您可以覆盖 RxJavaSchedulersHook,让您只需在一个位置进行更改。例如:
public MySuperCoolClient() {
if (BuildConfig.DEBUG) {
configureIoSchedulerToUseAsyncTaskThreadPool();
}
this.restApi = new Retrofit.Builder()
.baseUrl(Parameters.endpoint)
.addConverterFactory(GsonConverterFactory.create(gsonBuilder()))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
.create(RestApi.class);
}
private void configureIoSchedulerToUseAsyncTaskThreadPool() {
RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() {
@Override
public Scheduler getIOScheduler() {
return Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
}
下面的注释答案基于 Retrofit 1.6.1 - 将更新为最新版本。Retrofit 1.9.0不再允许你设置HttpExecutor
viaRestAdapter.Builder
接受的答案是朝着正确方向迈出的一步,但这让我感到不舒服。在实践中,您需要设置AsyncTask.THREAD_POOL_EXECUTOR
实时和测试版本或仅测试版本。
两者都设置意味着您的所有网络 IO 池将取决于 aysnc 队列实现,对于具有目标版本 ICS+ 的应用程序,它默认变为串行
仅设置测试意味着您的测试构建与您的实时构建不同,恕我直言,这不是一个开始测试的好地方。此外,由于异步池更改, 您可能会在旧设备上遇到测试问题。
上面已经正确地提到了Espresso
它AsyncTask.THREAD_POOL_EXECUTOR
。让我们四处寻找...
它是如何获得这个的?
谁/什么使用这个?
BaseLayerModule
有provideCompatAsyncTaskMonitor(ThreadPoolExecutorExtractor extractor)
返回一个AsyncTaskPoolMonitor
这是如何运作的?看一看!
它在哪里使用?
UiControllerImpl
具有在检查任何用户注册的 idlingResources 之前loopMainThreadUntilIdle()
手动调用的方法asyncTaskMonitor.isIdleNow()
idlingResourceRegistry.allResourcesAreIdle()
我猜测使用 Retrofit 我们可以使用该RestAdapter.Builder.setExecutors(...)
方法并传入我们自己的实例(或版本),使用与Android 上的 init相同AsyncTaskPoolMonitor
的 httpExecutor
Retrofit
@Override Executor defaultHttpExecutor() {
return Executors.newCachedThreadPool(new ThreadFactory() {
@Override public Thread newThread(final Runnable r) {
return new Thread(new Runnable() {
@Override public void run() {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
r.run();
}
}, RestAdapter.IDLE_THREAD_NAME);
}
});
}
(从这里)
并将其包装在IdlingResource
界面中以在我们的测试中使用!!
唯一的问题是在依赖于主 Looper 的 mainThread 上Retrofit
使用单独的回调,这可能会导致问题,但我暂时假设 Espresso 也与此相关。需要调查这个。Executor
Retrofit 2 使用 okhttp3,而后者又使用了一个调度程序。Jake Wharton 创建了这个库来监控调度程序的空闲情况。您将像这样创建 IdlingResource:
IdlingResource resource = OkHttp3IdlingResource.create("OkHttp", okHttpClient);
请注意,这可能不足以用于成功的 Espresso 测试(我已经尝试过),因为 IdlingResource 可能会在 http 调用之前或之后说它是空闲的,并且您的 Espresso 测试将执行并失败而不是等待。
对于这些情况,我的建议是使用线程池来启动任何后台任务并制作一个 IdlingResource 包装这个线程池。有关更多信息,请参阅本文:https ://medium.com/@yair.kukielka/idlingresource-dagger-and-junit-rules-198e3ae791ff
如果您使用的是 Asynctasks,则无需执行任何操作,因为 Espresso 已经知道如何等待它们:它使用AsyncTaskPoolMonitor,它是 Asynctask 线程池的包装器。
如果您使用的是自己的线程池(这是我的情况),您可以使用这个类来包装您的执行程序,以便 Espresso 可以知道它何时空闲。
这篇很棒的文章解释了它是如何工作的。我在我的项目中尝试过,它很棒!使用 dagger,我获得了我的线程池并将其包装在 junit @rule 中的 IdlingResource 中。