Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Espressoテストコードの同期処理を究める / Synchronization capabilities of Espresso

TOYAMA Sumio
February 07, 2018

Espressoテストコードの同期処理を究める / Synchronization capabilities of Espresso

DroidKaigi 2018のセッション「Espressoテストコードの同期処理を究める」(2018/2/8 15:40- @ Room5) の発表スライドです。

TOYAMA Sumio

February 07, 2018
Tweet

More Decks by TOYAMA Sumio

Other Decks in Programming

Transcript

  1. /3- p'&: " 2 (TOYAMA Sumio) @sumio_tym (Twi0er) / @sumio

    (GitHub) p#0: DeNA SWET  (So<ware Engineer in Test) p$(:    p : pSTAR (  ,.) p@IT1 %*)    (UI Automator / Appium+!) 2
  2. -   pAndroidUI #Espresso 0/7'683%  9 1) 

    p.5,(1)   3 0/7'"$2 Espresso ! sleep() 4+ &*
  3.  ! 1. Espresso   2. Espresso# 3. 

     "   4. ($ )% 5. sleep() '  & 4
  4. Espresso  pAndroid)/ UI https://d.android.com/training/testing/espresso/index.html p%3$28#3 pEspresso Test Recorder pDroidKaigi

    2017 ( Espresso   07 https://goo.gl/D73jBN p 69+", "4 p. 5!*1&    6  https://developer.android.com/training/testing/espresso/index.html -'
  5. Espresso   (https://goo.gl/VSHigS) prepositoriesgoogle() pdependencies    pconfiguration:

    androidTestImplementation pgroup: com.android.support.test.espresso pmodule: espresso-core pversion: 3.0.1 ptestInstrumentationRunner: "android.support.test.runner.AndroidJUnitRunner" 7
  6. Espresso      (# $"OFF) p 

      p   p % !  8
  7. Espresso psrc/androidTest/java  pAndroid Test Support Library  9 @RunWith(AndroidJUnit4.class)

    public class MyEspressoTest { @Rule public ActivityTestRule<...> activityActivityTestRule = ...; ... }
  8. Espresso API   OK perform()check()  10 onView(ViewMatcher) .perform(ViewAction)

    .check(ViewAssertion); p ViewMatcher  View  p ViewAction p  ViewViewAssertion 
  9. Espresso API  API   https://goo.gl/hx6YPo 11 onView(ViewMatcher) .perform(ViewAction)

    .check(ViewAssertion); p ViewMatcher  View  p ViewAction p  ViewViewAssertion 
  10.    Espresso   p(* p+, ' p!#"&

    $% ) p  p ' pAPI  12
  11.    Espresso    p p !

     p   p  p  pAPI  13 !
  12.   1. Espresso   2. Espresso  3.

        4. " # 5. sleep()!   14
  13. !'")(. +$ &/0  - 3, *  (https://goo.gl/poLgkZ) p

     pAsyncTask   p%2IdlingResource &(#1) 15
  14. ',(.-4  1)+  $56 3820 (https://goo.gl/poLgkZ) p"&% pAsyncTask!#& %

    p  IdlingResource  17 AsyncTask1/  *7  Espresso  
  15.  1. Espresso  2. Espresso  3.  

     4.  5. sleep()   19
  16. .2 / "$  ! /   2 pandroid.support.test.espresso

    pIdlingResource pIdlingRegistry .2 #   1. IdlingResource ' )( IdlingRegistry &% 20
  17. IdlingResource 21 public interface IdlingResource { public String getName(); public

    boolean isIdleNow(); // # %& ? ("* + ! IdlingResource!  $),' "
  18. IdlingResource 23 //  public void registerIdleTransitionCallback( ResourceCallback callback); public

    interface ResourceCallback { public void onTransitionToIdle(); } } !"   callback.onTransitionToIdle()   (  )#!!
  19. IdlingResource  24 Espresso   IdlingResource onView()... isIdleNow() UI

      onTransitionToIdle() registerIdleTransitionCallback(this) false   UI
  20. IdlingResource 25 private ResourceCallback callback; private boolean idle = false;

    public void registerIdleTransitionCallback( ResourceCallback callback) { this.callback = callback } // 
  21. IdlingResource  26 // private ResourceCallback callback; // private boolean

    idle = false; public void backgroundWorkDone() { idle = true; callback.onTransitionToIdle(); } //      
  22. IdlingResource  27 // private ResourceCallback callback; // private boolean

    idle = false; public boolean isIdleNow() { if (callback != null && idle) { callback.onTransitionToIdle(); } return idle; }      
  23. IdlingRegistry IdlingResource  / p     

    28 private IdlingRegistry reg; ... reg = IdlingRegistry.getInstance();
  24. IdlingRegistry IdlingResource' %#/$" 29 p IdlingResource ( !&  )

    reg.register(idlingResource); p IdlingResource (%#  ) reg.unregister(idlingResource);
  25. IdlingRegistry I P pIdlingRegistry: Espresso 3.0  p API: pEspresso.registerIdlingResources()

    pEspresso.unregisterIldingResources() p ) ./7 / :/. p ) A    p / 1::7 ( /: / 66 4/ 65 30
  26.  p&+',/*(3-  IdlingResource% # )7 1 p3 $!")7 

    p    )78 pIdlingResource)7   IdlingRegistry64/.5  p02   64  31
  27.   1. Espresso   2. Espresso" 3. 

    !   4.  5. sleep() $  # 32
  28. CountingIdlingResource%$ p'# !(   ")   pincrement(): ")

      ('# & ) pdecrement(): ")   ('#!(& ) 34   0 
  29. CountingIdlingResource 35 AtomicInteger counter = new AtomicInteger(0); volatile ResourceCallback callback;

    @Override public boolean isIdleNow() { return counter.get() == 0; } @Override public void registerIdleTransitionCallback( ResourceCallback callback) { this.callback = callback; } ※ Google's Maven Repository h4ps://goo.gl/aMUS5n     
  30. CountingIdlingResource # 36 public void increment() { counter.getAndIncrement(); } public

    void decrement() { int count = counter.decrementAndGet(); if (count == 0 && null != callback) { // 0  ! callback.onTransitionToIdle(); } } } ※ Google's Maven Repository h4ps://goo.gl/aMUS5n   "
  31. RxJava2  API 39 RxJavaPlugins .setScheduleHandler(oldAction ->{ Log.d(TAG,"  ");

    return () -> { Log.d(TAG,""); oldAction.run(); Log.d(TAG,""); }; }); p  API    
  32.   41 //  private CountingIdlingResource resource = new

    CountingIdlingResource("Rx"); private IdlingRegistry registry = IdlingRegistry.getInstance();
  33.  42 @Before public void setUp() { RxJavaPlugins.setScheduleHandler( oldAction ->

    () -> { try { resource.increment(); oldAction.run(); } finally { resource.decrement(); } }); registry.register(resource); }    
  34. : A RxJava A) 44 // ( // A )

    ) @Rule public ActivityTestRule<MyActivity> activityRule = new ActivityTestRule<>( MyActivity.class, false, false); @Before public void setUp() { ... // A) registry.register(resource); activityRule.launchActivity(null); }
  35.    :  RxJava Espresso   in

    Rx Ja Night Vol.2 h7ps://goo.gl/GBG8r1 46
  36. idling-concurrent   (β ) com.android.support.test.espresso.idling: idling-concurrent:3.0.1 pIdlingThreadPoolExecutor pThreadPoolExecutor IdlingResource(

    pThreadPoolExecutor new  IdlingThreadPoolExecutor new register unregister ) 48 Espresso IdlingResource(
  37. EspressoIdlingResource  IdlingThreadPoolExecutor pOkH3p   50 OkHttpClient okHttpClient =

    new OkHttpClient.Builder() .dispatcher( new Dispatcher( new IdlingThreadPoolExecutor( "OkHttp", ...))) .build();
  38. Espresso!$ IdlingResource' IdlingThreadPoolExecutor pOkH3p %#  51 OkHttpClient okHttpClient =

    new OkHttpClient.Builder() .dispatcher( new Dispatcher( new IdlingThreadPoolExecutor( "OkHttp", ...))) .build(); OkHttp ThreadPoolExecutor (Dispatcher. executorService()"()    & h3ps://goo.gl/UVdQ9B "(
  39. UriIdlingResource! 53 Client GET A <img src="B"> ... <img src="C">

    GET B and C 1  2            
  40. 0# '... pIdlingResource "(:  pIdlingResource .*/&-:  p ,$

    ) +  57    (IdlingResource /%! )
  41. 1 2$("   pIdlingResource *:  pIdlingResource /-/&.: 

     p # /- + pIdlingResource  p0!)  pEspresso',API IdlingResource  /- % 59
  42.   +*  p'$.-#)implementation /( com.android.support.test.espresso: espresso-idling-resource:3.0.1 p, 3

     (Espresso"%,!&) pIdlingRegistry pIdlingResource pCountingIdlingResource 60
  43.  p CountingIdlingResource/EF =, p$<*/E20%A. p 72? RxJavaC(381> & )-H@

    p GIdlingResource/EH@ p IdlingResource+0#;6'4  :9 p"# !;6D5B 61
  44.   1. Espresso   2. Espresso  3.

        4. " #! 5. sleep()  62
  45. IdlingResource(2     p%+0 $ 4,  

    &. (RxJava!#*'/ ) p31API" "#-)    &. 64
  46. IdlingResource UI Automator  pSelenium 5 API View 1 65

    // "OK" // assertThat( uiDevice.wait( Until.hasObject(By.text("OK")), 5000L), is(true));
  47. UI Automator  p   com.android.support.test.uiautomator: uiautomator-v18:2.1.3 p @Before

    66 private UiDevice uiDevice; @Before public void setUp() throws Exception { uiDevice = UiDevice.getInstance( InstrumentationRegistry .getInstrumentation()); }
  48. UI Automator # p $ )uiDevice.wait() # p Until 

     %"!& pfindObject() pfindObjects() pgone() phasObject() 67 uiDevice.wait(' %",  ()
  49. UI Automator: Tips 68 /** I */ String toResName(int resId)

    { return InstrumentationRegistry .getTargetContext() .getResources() .getResourceName(resId); } ID(int)UI   p UI Automator D p ID I
  50. UI Automator: Tips 70 // R.id.text // " UiObject2 textView

    = uiDevice.wait(Until.findObject( By.res(toResName(R.id.text))), 5000L); assertThat(textView.wait( Until.textEquals("OK"), 5000L), is(true));  AND UI   p UiObject2 wait
  51. URL p Kenta Kase RxJava  Espresso  in DroidKaigi

    Prelude https://goo.gl/zUQEFi p Iñaki VillarEspresso, Beyond the basicsin 360|AnDev 2017 https://goo.gl/FG7sLf p Espresso 3.0.1  p https://goo.gl/VidZGa (espresso-core) p https://goo.gl/aMUS5n (espresso-idling-resource) p  Espresso Idling Resources https://goo.gl/PGzjWe 72
  52. &!URL ($,) p  RxJava-( ) Espresso " in Rx

    Ja Night Vol.2 h;ps://goo.gl/GBG8r1 p %. Espresso+'*"  in DroidKaigi 2017 h;ps://goo.gl/D73jBN p % UI Automator# in DroidKaigi 2016 h;ps://goo.gl/NQV8GP 73
  53.  Espresso UI'$ !  # p $" pIdlingResource( 

    p)&IdlingResource(*% p+ IdlingResource    $ 74