我正在编写集成测试,在UI中执行操作,使用 Retrofit 启动网络调用。
我知道我需要实现一个CountingIdlingResource
,但我想以正确的方式去做(如果已经完成,不要重新发明轮子)。
有没有人在其应用的 Espresso 测试套件中实施IdlingResource
等待网络请求执行?
更多信息here。
答案 0 :(得分:22)
对此最直接的解决方案是:基本上将Retrofit的线程池执行器替换为AsyncTask(根据linked Google group discussion中非常有帮助的Nick的推荐)。我是这样做的:
new RestAdapter.Builder()
.setEndpoint(LOCLSET_SERVER_URL)
.setExecutors(AsyncTask.THREAD_POOL_EXECUTOR,
new MainThreadExecutor())
.build();
我不确定这是否是最合适的解决方案,但它是我能够工作的最快最理智的解决方案。请记住,这只适用于ICS +。
答案 1 :(得分:4)
如果您正在使用RxJava Observables和Retrofit 2.0,那么您可以使用.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);
}
});
}
答案 2 :(得分:1)
以下注释答案基于Retrofit 1.6.1 - 将更新为最新版本。 Retrofit 1.9.0不允许您再通过HttpExecutor
设置RestAdapter.Builder
接受的答案是向正确方向迈出的一步,但这让我感到不舒服。在实践中,您需要为活动和放大器设置AsyncTask.THREAD_POOL_EXECUTOR
。测试仅构建OR测试版本。
两者的设置意味着您的所有网络IO池都将取决于aysnc队列实现,该实现变为serial by default for apps with target versions ICS+
仅为测试设置意味着您的测试版本与您的实时版本不同,而imho不是开始测试的好地方。此外,由于异步池更改,可能在旧设备上遇到测试问题。
上面正确地提到Espresso
已经挂钩AsyncTask.THREAD_POOL_EXECUTOR
。让我们四处寻找...
如何获得这个?
谁/什么用这个?
BaseLayerModule
有provideCompatAsyncTaskMonitor(ThreadPoolExecutorExtractor extractor)
,返回AsyncTaskPoolMonitor
这是如何工作的?看看吧!
它在哪里使用?
UiControllerImpl
方法loopMainThreadUntilIdle()
在检查任何用户注册的idlingResources asyncTaskMonitor.isIdleNow()
之前手动调用idlingResourceRegistry.allResourcesAreIdle()
我在使用Retrofit进行猜测时,我们可以使用RestAdapter.Builder.setExecutors(...)
方法,并使用与AsyncTaskPoolMonitor
相同的http Executor
传入我们自己的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);
}
});
}
(来自here)
将其包装在IdlingResource
界面中,以便在我们的测试中使用!!
唯一的问题是Retrofit
使用mainThread上依赖主Looper的单独Executor
进行回调,这个可能会导致问题但我假设目前Espresso也与此相关。需要研究一下。
答案 3 :(得分:0)
如果你正在使用Asynctasks,你不需要做任何事情,因为Espresso已经知道如何等待它们:它使用AsyncTaskPoolMonitor,这是Asynctask线程池的包装。
如果您正在使用自己的线程池(这是我的情况),您可以使用this类来包装您的执行程序,以便Espresso可以知道它何时处于空闲状态。
This精彩的帖子解释了它是如何运作的。我尝试过我的项目,这很棒!使用dagger,我得到了一个我的线程池并将它包装在junit @rule中的IdlingResource中。
答案 4 :(得分:0)
Retrofit 2使用okhttp3,后者又使用调度程序。杰克沃顿创建了this库来监控调度员的闲置状态。您可以像这样创建IdlingResource:
IdlingResource resource = OkHttp3IdlingResource.create("OkHttp", okHttpClient);
请注意,这可能不足以用于成功的Espresso测试(我已经尝试过),因为IdlingResource可能会说它在http调用之前或之后处于空闲状态,而Espresso测试将执行并失败而不是等待。
我对这些情况的建议是使用线程池来启动任何后台任务,并使一个IdlingResource包装此线程池。有关详细信息,请参阅此文章:https://medium.com/@yair.kukielka/idlingresource-dagger-and-junit-rules-198e3ae791ff