EspressoのテストをAndroidの最新トレンドに対応させよう / Make Espresso testing follow the cutting edge in Android development

17997dee8a3da090f62d8cf8c494d8ff?s=47 TOYAMA Sumio
February 07, 2019

EspressoのテストをAndroidの最新トレンドに対応させよう / Make Espresso testing follow the cutting edge in Android development

DroidKaigi 2019のセッション「EspressoのテストをAndroidの最新トレンドに対応させよう」の発表スライドです。
サンプルコードのGitHubリポジトリは
https://github.com/sumio/android-sunflower-for-droidkaigi2019
です。

17997dee8a3da090f62d8cf8c494d8ff?s=128

TOYAMA Sumio

February 07, 2019
Tweet

Transcript

  1. Espresso   Android  2019.02.07   (sumio_tym) DroidKaigi

    2019 @ Day1 Room2 12:50-
  2. $ p :  # (TOYAMA Sumio) @sumio_tym (Twitter) /

    @sumio (GitHub) p  : DeNA SWET  (Software Engineer in Test) p :  p : Android "! https://peaks.cc/sumio_tym/android_testing 2
  3. %  3 Espresso(  Android )  "*! 

    AndroidX)  Kotlin& AAC (Android Architecture Components) +#& Kotlin AndroidX AAC Android$&   % ' 
  4. % * p #'&+  p Espresso  p "!

    : Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 4 Kotlin AndroidX AAC Kotlin AndroidX
  5. % * p #'&+  p Espresso  p "!

    : Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 5 Kotlin AndroidX AAC Kotlin AndroidX
  6. : Espresso p Android'+ UI https://developer.android.com/training/testing/espresso/ p ATSL (Android Testing

    Support Library)AndroidX Test # p % -$ p Espresso Test Recorder)    p    ". p * /!(,&   6 () () This logo image is reproduced from work created and shared by the Android Open Source Project (https://developer.android.com/license) and used according to terms described in the Creative Commons 2.5 Attribution License (http://creativecommons.org/licenses/by/2.5/).
  7. : Espresso API Espresso OK perform()check()%# 7 onView(ViewMatcher).perform(ViewAction) .check(ViewAssertion) ViewMatcher

    ViewViewAction → ViewViewAssertion$  "! 
  8. : Espresso API Espresso!OK $ API (%"&# https://d.android.com/training/testing/espresso/cheat-sheet 8 onView(ViewMatcher).perform(ViewAction)

    .check(ViewAssertion) ViewMatcher ViewViewAction → ViewViewAssertion'  %"
  9.  : AndroidX AndroidX = Support Library + Android Testing

    Support Library + Jetpack components https://d.android.com/jetpack/androidx/ p   androidx.*  p     p Android Studio    9
  10.  : AAC (Android Architecture Components) %&" "  !

     #$ https://d.android.com/topic/libraries/architecture/ p 2018  Android Jetpack  10 pViewModel pLiveData pRoom pNavigation pPager pWorkManager...
  11.  ;8   p Espresso p CN62I?H$-AMO95 p API#%!%1J

     p AndroidX p D/  >3B4G7 ("+&.F0 *% p AAC (Android Architecture Components) p E:=),@K<.*'.%L 11
  12. % * p #'&+  p Espresso  p "!

    : Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 12 Kotlin AndroidX AAC Kotlin AndroidX
  13.   :   p Android Studio 3.3 p

       p Use AndroidX artifacts p (LanguageKotlin) 13 AndroidX
  14.   :   p Android Studio  RefactorMigrate

    to AndroidX... 14 AndroidX
  15. build.gradle 15 android { ... testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } dependencies {

    ... androidTestImplementation 'androidx.test:runner:...' androidTestImplementation 'androidx.test.espresso:espresso-core:...' AndroidX
  16.    16  Latest Stable Version() androidx.test:runner 1.1.1

    androidx.test:rules 1.1.1 androidx.test.ext:junit-ktx 1.1.0 androidx.test:core-ktx 1.1.0 androidx.test.espresso:espresso-core 3.1.1 androidx.test.espresso:espresso-contrib 3.1.1 ()2019127  ActivityScenario () AndroidJUnit4() ActivityScenarioRule () AndroidX
  17. KotlinjvmTarget 1.8 : androidx.test.ext:junit-ktxJVM 1.7 17 tasks.withType(org.jetbrains.kotlin.gradle.tasks. KotlinCompile).all { sourceCompatibility

    = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 kotlinOptions { jvmTarget = '1.8' } } AndroidX
  18. KotlinjvmTarget 1.8   activityScenarioRule(intent: Intent? = null)  

     18 AndroidX
  19.    p )(AndroidX'Espresso  p &$" Use AndroidX

    artifacts p .+ Migrate to AndroidX...  p - ,   %  #*! p androidx.test.ext:junit-ktx p androidx.test:core-ktx 19 AndroidX
  20. % * p #'&+  p Espresso  p "!

    : Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 20 Kotlin AndroidX AAC Kotlin AndroidX
  21. ,%*%): Android Sunflower p Android Jetpack (≒AAC)  2 

    ,%*%) https://github.com/googlesamples/android-sunflower p %+(&,/3Kotlin6- 21  " #1 (04 )   .5 ($Android Sunflower%) ),'!#78   Copyright 2018 Google, Inc. Licensed under the Apache License, Version 2.0. Select text used for describing the plants are used from Wikipedia via CC BY-SA 3.0 US.
  22. Sunflower  My garden Plant list   22

  23. Sunflower Plant list    → Plant details 

    23
  24. Sunflower Plant details FAB → My garden   24

  25. % * p #'&+  p Espresso  p "!

    : Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 25 Kotlin AndroidX AAC Kotlin AndroidX
  26. Espresso Test Recorder:  #  p Android Studio 3.2

    (AndroidXKotlin! ) p  "    p adb$Android/  26 AndroidX Kotlin
  27. Espresso Test Recorder:    27 KotlinAndroidX  

     p    p    AndroidX Kotlin
  28. Espresso Test Recorder: "&# p /adb'! p  % 

     Android Studio p RunRecord Espresso Test p  %$ p Record Your Test  28 AndroidX Kotlin
  29. Espresso Test Recorder: ' " p ! ' p '

    Record Your Test % ($& 1  #() 29 AndroidX Kotlin
  30. Espresso Test Recorder: Assertion p Record Your Test  Add

    Assertion   30 AndroidX Kotlin
  31. Espresso Test Recorder: Assertion p     

      31 AndroidX Kotlin
  32. Espresso Test Recorder: Assertion p    p Edit

    assertionSave Assertion 32 AndroidX Kotlin
  33. Espresso Test Recorder:  p Record Your Test  OK

      p Specify a test class for your test    p Test class name: () p Test class language: Kotlin 33 AndroidX Kotlin
  34. Espresso Test Recorder: ATSL or AndroidX Test? Espresso Test Recorder

     ( ) AndroidX   AndroidX Test  ATSL (Android Testing Support Library) AndroidX     34 AndroidX Kotlin
  35. Espresso Test Recorder:     35 Espresso Test

    Recorder   p AndroidJUnit4deprecated p ActivityTestRuledeprecated  () This text is reproduced from work created and shared by the Android Open Source Project (https://developer.android.com/license) and used according to terms described in Apache License, Version 2.0. URL: https://d.android.com/reference/androidx/test/ext/junit/rules/ActivityScenarioRule ()
  36. Espresso Test Recorder: deprecatedAndroidJUnit4 ( import ( ) 36 import

    androidx.test.runner.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 AndroidX Kotlin
  37. Espresso Test Recorder:    deprecatedAndroidJUnit4  import Show

    Intention Actions (Option+Enter)  37 AndroidX Kotlin
  38. Espresso Test Recorder:     ActivityTestRule ActivityScenarioRule 38

    AndroidX Kotlin
  39. Espresso Test Recorder:    39 @Rule @JvmField var

    mActivityTestRule = ActivityTestRule(GardenActivity::class.java) @get:Rule val activityScenarioRule = activityScenarioRule<GardenActivity>() Java getter    API: activityScenarioRule read-only  AndroidX Kotlin
  40. activityScenarioRule 40 @get:Rule val activityScenarioRule = ActivityScenarioRule(GardenActivity::class.java) @get:Rule val activityScenarioRule

    = activityScenarioRule<GardenActivity>() Kotlin jvmTarget 1.8  AndroidX Kotlin   
  41. ActivityTestRule vs ActivityScenarioRule Activity   p ActivityTestRule p ActivityScenarioRule

    41 @get:Rule val activityTestRule = ActivityTestRule(GardenActivity::class.java) @get:Rule val activityScenarioRule = activityScenarioRule<GardenActivity>() AndroidX Kotlin
  42. ActivityTestRule vs ActivityScenarioRule Activity    p ActivityTestRule 42

    @get:Rule val activityTestRule = ActivityTestRule(GardenActivity::class.java, false, false) ... // Activity   activityTestRule.launchActivity(null) AndroidX Kotlin
  43. ActivityTestRule vs ActivityScenarioRule Activity    p ActivityScenario (ActivityScenarioRule)

    43 // Rule    // Activity   launchActivity<GardenActivity>(null).use { ... //   ActivityRESUMED } AndroidX Kotlin
  44. ActivityTestRule vs ActivityScenarioRule ActivityScenario Activity   / 44 //

    Activity launchActivity<GardenActivity>(null) .use { scenario -> scenario.moveToState(State.STARTED) } AndroidX Kotlin scenario.onActivity { ... } (Espresso) 
  45.    p Recorder"%*#  ( ) p "%')

    Test class languageKotlin OK p AndroidX& AndroidX Test  p 2! $ p AndroidJUnit4 ( p ActivityTestRule → ActivityScenario / ActivityScenarioRule 45 AndroidX Kotlin
  46. % * p #'&+  p Espresso  p "!

    : Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 46 Kotlin AndroidX AAC Kotlin AndroidX
  47. Espresso Test Recorder ! 47 Recorder "  p %

           p $   Kotlin PageObject  (#) 
  48. PageObject$$ 2'(,4  https://github.com/SeleniumHQ/selenium/wiki/PageObjects p %6#(Page ) &5 p Page#:

       ! p "$(9/) or )0.+*- p !8 7 Page   p 3Page#! 1 48 Kotlin
  49. Sunflower PageObject MyGardenPage p // goPlantList(): PlantListPage p // plantName

    // assertPlanted(plantName: String): MyGardenPage 49 Kotlin
  50. Sunflower PageObject PlantListPage p // plantName // showPlantDetail(plantName: String): PlantDetailPage

    p // goBackMyGarden(): MyGardenPage 50 Kotlin
  51. Sunflower PageObject PlantDetailPage p // ) )( goBackPlantList(): PlantListPage p

    / addToMyGarden(): PlantDetailPage 51 Kotlin
  52. &0: (. PageObject)/ p % $#!# https://github.com/sumio/android-sunflower-for-droidkaigi2019 p , "%*

     +'- 1  52 Kotlin
  53. #3: *0 PageObject ,1 *0 ( !&) (: droidkaigi/step0 1.

    PlantList .$  2. "Avocado" " (PlantDetail .$ ) 3. FAB2 My Garden /'  4. PlantDetail 4 5. My Garden 4 6. "Avocado"%+  -)  53 Kotlin
  54.   54 Kotlin :   PageObject

  55. :   PageObject  Android Studio p Move Line

    Up/Down p RefactorExtractMethod p RefactorExtractVariable 55 Opt + Shift + ↑/↓ Opt + Command + M Opt + Command + V macOS  Kotlin
  56.  :  PageObject ! Android Studio p RefactorInline p

    RefactorMove ( ) p Show Intention Actions 56 macOS  F6 Opt + Enter Opt + Command + N Kotlin
  57.   57 Step1  Step2-4    Page

      (  ) Step5  return value   PageObject
  58. 58 Step1   Step2-4     Page

     (  ) Step5  return value  PageObject
  59. Step1   Page    59 public 

     Extract Method Opt + Command + M Kotlin
  60. Step1   : droidkaigi/step1 60 Kotlin

  61. 61 Step1   Step2-4     Page

     (  ) Step5  return value  PageObject
  62. Step2     62 Move Line Down Opt

    + Shift + ↓ Kotlin
  63. Step2      : droidkaigi/step2 63 

     Kotlin
  64. Step3        64 RefactorMove

    F6 Kotlin
  65. Step3    ! !   65 Move

     Page  Kotlin
  66. Step3    66   childAtPosition (Recorder )

    PageUtils.kt goPlantList MyGardenPage.kt assertPlanted showPlantDetail PlantListPage.kt goBackMyGarden goBackPlantList PlantDetailPage.kt addToMyGarden Kotlin
  67. Step3   67   : droidkaigi/step3 Move 

    () Kotlin
  68. Step4 object 68    object Kotlin

  69. Step4 object 69 Show Intention Actions    

      Show Intention Actions Opt + Enter Kotlin
  70. Step4   object 70  : droidkaigi/step4 Page 

     Kotlin
  71. 71 Step1   Step2-4     Page

     (  ) Step5  return value  PageObject
  72. Step5  return   72  PageObject return Show

    Intention Actions Opt + Enter Kotlin
  73. Step5   return  73  : droidkaigi/step5 return

    type Kotlin
  74. 74 Step1   Step2-4     Page

     (  ) Step5  return value  PageObject
  75. 75 Kotlin    

  76.  76  Kotlin

  77.  77   Page  OK Kotlin

  78.  :   p MyGardenPage.assertPlanted() ( '!' # 

    &   p "%$: droidkaigi/extra 78 Kotlin
  79.    p Espresso Test Recorder  PageObject 

     p Android Studio   ( ) p Kotlin Move  79 Kotlin
  80. % * p #'&+  p Espresso  p "!

    : Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 80 Kotlin AndroidX AAC Kotlin AndroidX
  81. % 5'#UI13  * p View.9 p ;)"/(ID )+8,$ 

    p  2 p 4!(-&7:<60    81 AAC AAC 
  82. AAC  ! p Room:  p LiveData RxJava !

    p Pager:   p LivePagedListBuilderRxPagedListBuilder p WorkManager:  82 ArchTaskExecutor Executors. newFixedThreadPool() AAC
  83. AAC  ! p Room:  p LiveData RxJava !

    p Pager:   p LivePagedListBuilderRxPagedListBuilder p WorkManager:  83 ArchTaskExecutor Executors. newFixedThreadPool() AAC
  84. ArchTaskExecutor 84 p AAC   p  CountingTaskExecutorRule 

    androidx.arch.core:core-testing:2.0.0 AAC
  85. ArchTaskExecutor:    85 AAC @get:Rule val countingRule =

    CountingTaskExecutorRule() @Test fun myTest() { onView(...).perform(...) // AAC   countingRule..drainTasks(1, TimeUnit.MINUTES) onView(...).perform(...) ... }   
  86. ArchTaskExecutor: G S 86 p TaskExecutorWithIdlingResourceRule  p B /

    . / AAC @get:Rule val executorRule = TaskExecutorWithIdlingResourceRule() Rule L: OK
  87. AAC  ! p Room:  p LiveData RxJava !

    p Pager:   p LivePagedListBuilderRxPagedListBuilder p WorkManager:  87 ArchTaskExecutor Executors. newFixedThreadPool() AAC
  88. ArchTaskExecutor :    88 ThreadPoolExecutor  p WorkManager

    import androidx.work.Configuration ... val executor = ... val configuration = Configuration.Builder() .setExecutor(executor) .build() WorkManager.initialize(context, configuration) AAC
  89. ArchTaskExecutor: # $' ! 89 IdlingThreadPoolExecutor"% androidx.test.espresso.idling:idling-concurrent:3.1.1 val executor =

    IdlingThreadPoolExecutor(...) val configuration = Configuration.Builder() .setExecutor(executor) .build() WorkManager.initialize(context, configuration) AAC   & ( https://bit.ly/2Biu8QJ ) 
  90. ArchTaskExecutor:  "  90   (: CoroutineWorker) asCoroutineDispatcher()

     class MyWorker(...): CoroutineWorker(...) { override val coroutineContext: CoroutineDispatcher get() { val executor = IdlingThreadPoolExecutor(...) return executor.asCoroutineDispatcher() } ... AAC CoroutineWorker  ! 
  91.    p AAC(!%     

       '" p ArchTaskExecutor&   p $#Executor&   p Kotlin &   91
  92. % * p #'&+  p Espresso  p "!

    : Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 92 Kotlin AndroidX AAC Kotlin AndroidX
  93. $#  93 p EspressoAndroidXKotlin )"*!  p AndroidX) Recorder

    OK p ,+ 'deprecated -&  (AndroidJUnit4ActivityScenarioRule) p PageObject  Kotlin  (%
  94. !   94 p AAC Espresso%   *"(

     ) p      ' $&#
  95. URL p AndroidX Test https://github.com/android/android-test p Yuki AnzaiAndroidX Testin Android

    Dev Summit 2018  https://speakerdeck.com/yanzm/androidx-test p AndroidX Test   https://developer.android.com/jetpack/androidx/releases/test 95
  96. "URL ( ( +) p !) Espresso &#% in DroidKaigi

    2017 https://droidkaigi.github.io/2017/timetable.html#session-26 p  Espresso $ ' in DroidKaigi 2018 https://droidkaigi.jp/2018/timetable?session=16928 p *Android(+) https://peaks.cc/sumio_tym/android_testing 96
  97. 97 Espresso