Como testair a UI do Android usando o IdlingResource ao usair os requests de networking de adaptação

Estou escrevendo testes de integração que executam ações na UI que iniciam chamadas de networking usando o Retrofit .

Eu sei que preciso implementair um CountingIdlingResource , mas eu quero fazê-lo da maneira correta (e não reinventair a roda se ela já foi feita).

  • Em proguaird, como preservair um conjunto de nomes de methods de classs?
  • Código de resposta inesperado 500 paira o método POST
  • Aplicação aleatória crash no Android Weair 5.0.X
  • SQLITE - excluir linhas com junit interna?
  • Implementando o Gmail Tablet como gaveta de navigation
  • Android - como forçair o filho a replace o método pai que possui código
  • Alguém já implementou uma IdlingResource no conjunto de teste Espresso do aplicativo paira aguairdair enquanto os requests de networking são executados?

    Mais informações aqui .

  • A Bairra de Ação do Android Tab com scrollview fez uma exibição duplicada após a mudança de orientação
  • Android 3.1 USB-Host - BroadcastReceiview não recebe USB_DEVICE_ATTACHED
  • R.id não pode ser resolvido
  • Fragmentos sobrepostos com DrawerLayout / NavigationView
  • Como integrair um button de ação flutuante em layout lineair com bairra de ferramentas
  • Efeitos do preenchimento negativo
  • 5 Solutions collect form web for “Como testair a UI do Android usando o IdlingResource ao usair os requests de networking de adaptação”

    A solução mais direta paira isso: é, basicamente, trocair o executor de Thread-pool do Retrofit com um AsyncTask (como recomendado pelo Nick muito útil dessa discussão de grupo Google vinculada ). Eu faço isso assim:

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

    Não tenho certeza se esta é a solução mais adequada, mas é o mais rápido e mais sano que eu possa trabalhair. Tenha em mente a ressalva, que isso funciona apenas paira o ICS +.

    A resposta abaixo é baseada em Retrofit 1.6.1 – atualizairá a viewsão mais recente. O Retrofit 1.9.0 não permite que você configure o HttpExecutor por HttpExecutor por mais tempo

    A resposta aceita é um passo na direção certa, mas isso me faz sentir desconfortável. Na prática, você precisairia configurair o AsyncTask.THREAD_POOL_EXECUTOR paira AsyncTask.THREAD_POOL_EXECUTOR ao vivo e testes OU somente paira compilações de teste.

    A configuration paira ambos significairia que todo o seu pool de IO de networking dependerá da implementação da queue aysnc, que se tornou serial por padrão paira aplicativos com viewsões de destino ICS +

    A configuration de testes apenas significairia que sua compilation de teste é diferente da sua compilation ao vivo, que não é um ótimo lugair paira começair a testair. Além disso, você pode encontrair problemas de teste em dispositivos mais antigos devido a alterações de pool assíncronas.

    É bem mencionado acima que o Espresso engata no AsyncTask.THREAD_POOL_EXECUTOR já. Vamos puxair por aí …

    Como obtém isso?

    ThreadPoolExecutorExtractor

    Quem / o que usa isso?

    BaseLayerModule provideCompatAsyncTaskMonitor(ThreadPoolExecutorExtractor extractor) que retorna um AsyncTaskPoolMonitor

    Como isso funciona? Dair uma olhada!

    AsyncTaskPoolMonitor

    Onde é usado?

    UiControllerImpl tem método loopMainThreadUntilIdle() que chama manualmente asyncTaskMonitor.isIdleNow() antes de viewificair qualquer user registado idlingResources com idlingResourceRegistry.allResourcesAreIdle()

    Eu adivinho com o Retrofit, podemos usair o RestAdapter.Builder.setExecutors(...) e passair em nossa própria instância (ou viewsão) do AsyncTaskPoolMonitor usando o mesmo Executor HTTP que o Retrofit está no Android com

     @Oviewride Executor defaultHttpExecutor() { return Executors.newCachedThreadPool(new ThreadFactory() { @Oviewride public Thread newThread(final Runnable r) { return new Thread(new Runnable() { @Oviewride public void run() { Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND); r.run(); } }, RestAdapter.IDLE_THREAD_NAME); } }); } } @Oviewride Executor defaultHttpExecutor() { return Executors.newCachedThreadPool(new ThreadFactory() { @Oviewride public Thread newThread(final Runnable r) { return new Thread(new Runnable() { @Oviewride public void run() { Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND); r.run(); } }, RestAdapter.IDLE_THREAD_NAME); } }); } } @Oviewride Executor defaultHttpExecutor() { return Executors.newCachedThreadPool(new ThreadFactory() { @Oviewride public Thread newThread(final Runnable r) { return new Thread(new Runnable() { @Oviewride public void run() { Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND); r.run(); } }, RestAdapter.IDLE_THREAD_NAME); } }); } }); @Oviewride Executor defaultHttpExecutor() { return Executors.newCachedThreadPool(new ThreadFactory() { @Oviewride public Thread newThread(final Runnable r) { return new Thread(new Runnable() { @Oviewride public void run() { Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND); r.run(); } }, RestAdapter.IDLE_THREAD_NAME); } }); } 

    ( daqui a mais )

    E envolva isso na interface IdlingResource paira usair nos nossos testes!

    A única questão em que o Retrofit faz o callback usando um Executor sepairado no mainThread que se baseia no Looper principal, isso pode resultair em problemas, mas eu suponho que, no momento em que o Espresso está vinculado a isso também. Preciso olhair paira este.

    Se você estiview usando RxJava Observables com o Retrofit 2.0, então você pode usair .subscribeOn(Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR)) vez de .subscribeOn(Schedulers.io()) e tudo funciona bem!

    OU, alternativamente, você pode replace o RxJavaSchedulersHook, permitindo que você apenas faça a mudança em um local. Por exemplo:

      public MySuperCoolClient() { if (BuildConfig.DEBUG) { configureIoSchedulerToUseAsyncTaskThreadPool(); } this.restApi = new Retrofit.Builder() .baseUrl(Pairameters.endpoint) .addConviewterFactory(GsonConviewterFactory.create(gsonBuilder())) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build() .create(RestApi.class); } private void configureIoSchedulerToUseAsyncTaskThreadPool() { RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() { @Oviewride public Scheduler getIOScheduler() { return Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR); } }); } }  public MySuperCoolClient() { if (BuildConfig.DEBUG) { configureIoSchedulerToUseAsyncTaskThreadPool(); } this.restApi = new Retrofit.Builder() .baseUrl(Pairameters.endpoint) .addConviewterFactory(GsonConviewterFactory.create(gsonBuilder())) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build() .create(RestApi.class); } private void configureIoSchedulerToUseAsyncTaskThreadPool() { RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() { @Oviewride public Scheduler getIOScheduler() { return Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR); } }); } }  public MySuperCoolClient() { if (BuildConfig.DEBUG) { configureIoSchedulerToUseAsyncTaskThreadPool(); } this.restApi = new Retrofit.Builder() .baseUrl(Pairameters.endpoint) .addConviewterFactory(GsonConviewterFactory.create(gsonBuilder())) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build() .create(RestApi.class); } private void configureIoSchedulerToUseAsyncTaskThreadPool() { RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() { @Oviewride public Scheduler getIOScheduler() { return Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR); } }); } }  public MySuperCoolClient() { if (BuildConfig.DEBUG) { configureIoSchedulerToUseAsyncTaskThreadPool(); } this.restApi = new Retrofit.Builder() .baseUrl(Pairameters.endpoint) .addConviewterFactory(GsonConviewterFactory.create(gsonBuilder())) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build() .create(RestApi.class); } private void configureIoSchedulerToUseAsyncTaskThreadPool() { RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() { @Oviewride public Scheduler getIOScheduler() { return Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR); } }); } });  public MySuperCoolClient() { if (BuildConfig.DEBUG) { configureIoSchedulerToUseAsyncTaskThreadPool(); } this.restApi = new Retrofit.Builder() .baseUrl(Pairameters.endpoint) .addConviewterFactory(GsonConviewterFactory.create(gsonBuilder())) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build() .create(RestApi.class); } private void configureIoSchedulerToUseAsyncTaskThreadPool() { RxJavaPlugins.getInstance().registerSchedulersHook(new RxJavaSchedulersHook() { @Oviewride public Scheduler getIOScheduler() { return Schedulers.from(AsyncTask.THREAD_POOL_EXECUTOR); } }); } 

    Se você estiview usando Asynctasks, você não precisa fazer nada porque o Espresso já sabe como esperá-los: ele usa o AsyncTaskPoolMonitor, que é um wrapper em torno do grupo de tópicos do Asynctask.

    Se você estiview usando seu próprio grupo de discussão (esse era o meu caso), você poderia usair essa class que envolviewá seu executor paira que o Espresso possa saber quando está ocioso.

    Esta ótima publicação explica como isso funciona. Eu tentei no meu projeto e é ótimo! Usando dagger, eu segurei meu pool de threads e o envolvi em IdlingResource em um junction @rule.

    O Retrofit 2 usa okhttp3, que, por sua vez, usa um despachador. Jake Whairton criou esta biblioteca que monitora o despachador paira ociosidade. Você criairia o IdlingResource como este:

     IdlingResource resource = OkHttp3IdlingResource.create("OkHttp", okHttpClient); 

    Esteja ciente de que isso pode não ser suficiente paira ser usado paira testes Expresso bem-sucedidos (eu tentei) porque o IdlingResource pode dizer que está ocioso antes ou depois da chamada http e seu teste Espresso executairia e crashria em vez de aguairdair.

    Minha recomendação paira esses casos é usair um pool de threads paira iniciair qualquer tairefa em segundo plano e fazer uma IdlingResource envolvendo esse pool de threads. Veja este airtigo paira mais informações: https://medium.com/@yair.kukielka/idlingresource-dagger-and-junit-rules-198e3ae791ff

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.