如何在使用Retrofit网络请求时使用IdlingResource测试Android UI

时间:2014-04-17 20:03:24

标签: android integration-testing retrofit android-espresso

我正在编写集成测试,在UI中执行操作,使用 Retrofit 启动网络调用。

我知道我需要实现一个CountingIdlingResource,但我想以正确的方式去做(如果已经完成,不要重新发明轮子)。

有没有人在其应用的 Espresso 测试套件中实施IdlingResource等待网络请求执行?

更多信息here

5 个答案:

答案 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。让我们四处寻找...

如何获得这个?

ThreadPoolExecutorExtractor

谁/什么用这个?

BaseLayerModuleprovideCompatAsyncTaskMonitor(ThreadPoolExecutorExtractor extractor),返回AsyncTaskPoolMonitor

这是如何工作的?看看吧!

AsyncTaskPoolMonitor

它在哪里使用?

UiControllerImpl方法loopMainThreadUntilIdle()在检查任何用户注册的idlingResources asyncTaskMonitor.isIdleNow()之前手动调用idlingResourceRegistry.allResourcesAreIdle()

我在使用Retrofit进行猜测时,我们可以使用RestAdapter.Builder.setExecutors(...)方法,并使用与AsyncTaskPoolMonitor相同的http Executor传入我们自己的Retrofit实例(或版本)使用

在Android上初始化
@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