18

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

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

是否有人IdlingResource在其应用程序的Espresso测试套件中实现了等待网络请求执行的功能?

更多信息在这里

4

5 回答 5

22

最直接的解决方案是:基本上用 AsyncTask 替换 Retrofit 的线程池执行器(正如链接的 Google 小组讨论中非常有帮助的 Nick 所推荐的那样)。我这样做是这样的:

new RestAdapter.Builder()
               .setEndpoint(LOCLSET_SERVER_URL)
               .setExecutors(AsyncTask.THREAD_POOL_EXECUTOR,
                             new MainThreadExecutor())
               .build();

我不确定这是否是最合适的解决方案,但它是我可以开始工作的最快最理智的解决方案。请记住,这仅适用于 ICS+。

于 2014-05-03T22:26:39.157 回答
4

如果你在 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);
         }
      });
   }
于 2016-04-28T20:23:50.903 回答
1

下面的注释答案基于 Retrofit 1.6.1 - 将更新为最新版本。Retrofit 1.9.0不再允许你设置HttpExecutorviaRestAdapter.Builder

接受的答案是朝着正确方向迈出的一步,但这让我感到不舒服。在实践中,您需要设置AsyncTask.THREAD_POOL_EXECUTOR实时和测试版本或仅测试版本。

两者都设置意味着您的所有网络 IO 池将取决于 aysnc 队列实现,对于具有目标版本 ICS+ 的应用程序,它默认变为串行

仅设置测试意味着您的测试构建与您的实时构建不同,恕我直言,这不是一个开始测试的好地方。此外,由于异步池更改, 您可能会在旧设备上遇到测试问题。

上面已经正确地提到了EspressoAsyncTask.THREAD_POOL_EXECUTOR。让我们四处寻找...

它是如何获得这个的?

ThreadPoolExecutorExtractor

谁/什么使用这个?

BaseLayerModuleprovideCompatAsyncTaskMonitor(ThreadPoolExecutorExtractor extractor)返回一个AsyncTaskPoolMonitor

这是如何运作的?看一看!

AsyncTaskPoolMonitor

它在哪里使用?

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

我猜测使用 Retrofit 我们可以使用该RestAdapter.Builder.setExecutors(...)方法并传入我们自己的实例(或版本),使用与Android 上的 init相同AsyncTaskPoolMonitor的 httpExecutorRetrofit

@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

于 2015-02-25T18:36:17.573 回答
1

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

于 2016-08-02T02:13:34.337 回答
0

如果您使用的是 Asynctasks,则无需执行任何操作,因为 Espresso 已经知道如何等待它们:它使用AsyncTaskPoolMonitor,它是 Asynctask 线程池的包装器。

如果您使用的是自己的线程池(这是我的情况),您可以使用这个类来包装您的执行程序,以便 Espresso 可以知道它何时空闲。

这篇很棒的文章解释了它是如何工作的。我在我的项目中尝试过,它很棒!使用 dagger,我获得了我的线程池并将其包装在 junit @rule 中的 IdlingResource 中。

于 2016-03-31T03:00:58.400 回答