Share
Embed
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
です。
TOYAMA Sumio
February 07, 2019
Transcript
97 slides
-
Espresso Android 2019.02.07 (sumio_tym) DroidKaigi
2019 @ Day1 Room2 12:50- -
$ 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 Espresso( Android ) "*!
AndroidX) Kotlin& AAC (Android Architecture Components) +#& Kotlin AndroidX AAC Android$& % ' -
% * p #'&+ p Espresso p "!
: Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 4 Kotlin AndroidX AAC Kotlin AndroidX -
% * p #'&+ p Espresso p "!
: Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 5 Kotlin AndroidX AAC Kotlin AndroidX -
: 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/). -
: Espresso API Espresso OK perform()check()%# 7 onView(ViewMatcher).perform(ViewAction) .check(ViewAssertion) ViewMatcher
ViewViewAction → ViewViewAssertion$ "! -
: Espresso API Espresso!OK $ API (%"&# https://d.android.com/training/testing/espresso/cheat-sheet 8 onView(ViewMatcher).perform(ViewAction)
.check(ViewAssertion) ViewMatcher ViewViewAction → ViewViewAssertion' %" -
: AndroidX AndroidX = Support Library + Android Testing
Support Library + Jetpack components https://d.android.com/jetpack/androidx/ p androidx.* p p Android Studio 9 -
: AAC (Android Architecture Components) %&" " !
#$ https://d.android.com/topic/libraries/architecture/ p 2018 Android Jetpack 10 pViewModel pLiveData pRoom pNavigation pPager pWorkManager... -
;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 -
% * p #'&+ p Espresso p "!
: Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 12 Kotlin AndroidX AAC Kotlin AndroidX -
: p Android Studio 3.3 p
p Use AndroidX artifacts p (LanguageKotlin) 13 AndroidX -
: p Android Studio RefactorMigrate
to AndroidX... 14 AndroidX -
build.gradle 15 android { ... testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } dependencies {
... androidTestImplementation 'androidx.test:runner:...' androidTestImplementation 'androidx.test.espresso:espresso-core:...' AndroidX -
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 -
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 -
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 -
% * p #'&+ p Espresso p "!
: Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 20 Kotlin AndroidX AAC Kotlin AndroidX -
,%*%): 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. -
% * p #'&+ p Espresso p "!
: Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 25 Kotlin AndroidX AAC Kotlin AndroidX -
Espresso Test Recorder: # p Android Studio 3.2
(AndroidXKotlin! ) p " p adb$Android/ 26 AndroidX Kotlin -
Espresso Test Recorder: 27 KotlinAndroidX
p p AndroidX Kotlin -
Espresso Test Recorder: "&# p /adb'! p %
Android Studio p RunRecord Espresso Test p %$ p Record Your Test 28 AndroidX Kotlin -
Espresso Test Recorder: ' " p ! ' p '
Record Your Test % ($& 1 #() 29 AndroidX Kotlin -
Espresso Test Recorder: Assertion p Record Your Test Add
Assertion 30 AndroidX Kotlin -
Espresso Test Recorder: Assertion p
31 AndroidX Kotlin -
Espresso Test Recorder: Assertion p p Edit
assertionSave Assertion 32 AndroidX Kotlin -
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 -
Espresso Test Recorder: ATSL or AndroidX Test? Espresso Test Recorder
( ) AndroidX AndroidX Test ATSL (Android Testing Support Library) AndroidX 34 AndroidX Kotlin -
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 () -
Espresso Test Recorder: deprecatedAndroidJUnit4 ( import ( ) 36 import
androidx.test.runner.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 AndroidX Kotlin -
Espresso Test Recorder: deprecatedAndroidJUnit4 import Show
Intention Actions (Option+Enter) 37 AndroidX Kotlin -
Espresso Test Recorder: ActivityTestRule ActivityScenarioRule 38
AndroidX Kotlin -
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 -
activityScenarioRule 40 @get:Rule val activityScenarioRule = ActivityScenarioRule(GardenActivity::class.java) @get:Rule val activityScenarioRule
= activityScenarioRule<GardenActivity>() Kotlin jvmTarget 1.8 AndroidX Kotlin -
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 -
ActivityTestRule vs ActivityScenarioRule Activity p ActivityTestRule 42
@get:Rule val activityTestRule = ActivityTestRule(GardenActivity::class.java, false, false) ... // Activity activityTestRule.launchActivity(null) AndroidX Kotlin -
ActivityTestRule vs ActivityScenarioRule Activity p ActivityScenario (ActivityScenarioRule)
43 // Rule // Activity launchActivity<GardenActivity>(null).use { ... // ActivityRESUMED } AndroidX Kotlin -
ActivityTestRule vs ActivityScenarioRule ActivityScenario Activity / 44 //
Activity launchActivity<GardenActivity>(null) .use { scenario -> scenario.moveToState(State.STARTED) } AndroidX Kotlin scenario.onActivity { ... } (Espresso) -
p Recorder"%*# ( ) p "%')
Test class languageKotlin OK p AndroidX& AndroidX Test p 2! $ p AndroidJUnit4 ( p ActivityTestRule → ActivityScenario / ActivityScenarioRule 45 AndroidX Kotlin -
% * p #'&+ p Espresso p "!
: Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 46 Kotlin AndroidX AAC Kotlin AndroidX -
Espresso Test Recorder ! 47 Recorder " p %
p $ Kotlin PageObject (#) -
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 -
Sunflower PageObject MyGardenPage p // goPlantList(): PlantListPage p // plantName
// assertPlanted(plantName: String): MyGardenPage 49 Kotlin -
Sunflower PageObject PlantListPage p // plantName // showPlantDetail(plantName: String): PlantDetailPage
p // goBackMyGarden(): MyGardenPage 50 Kotlin -
Sunflower PageObject PlantDetailPage p // ) )( goBackPlantList(): PlantListPage p
/ addToMyGarden(): PlantDetailPage 51 Kotlin -
#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 -
: PageObject Android Studio p Move Line
Up/Down p RefactorExtractMethod p RefactorExtractVariable 55 Opt + Shift + ↑/↓ Opt + Command + M Opt + Command + V macOS Kotlin -
: PageObject ! Android Studio p RefactorInline p
RefactorMove ( ) p Show Intention Actions 56 macOS F6 Opt + Enter Opt + Command + N Kotlin -
57 Step1 Step2-4 Page
( ) Step5 return value PageObject -
58 Step1 Step2-4 Page
( ) Step5 return value PageObject -
Step1 Page 59 public
Extract Method Opt + Command + M Kotlin -
61 Step1 Step2-4 Page
( ) Step5 return value PageObject -
Step2 62 Move Line Down Opt
+ Shift + ↓ Kotlin -
Step2 : droidkaigi/step2 63
Kotlin -
Step3 64 RefactorMove
F6 Kotlin -
Step3 ! ! 65 Move
Page Kotlin -
Step3 66 childAtPosition (Recorder )
PageUtils.kt goPlantList MyGardenPage.kt assertPlanted showPlantDetail PlantListPage.kt goBackMyGarden goBackPlantList PlantDetailPage.kt addToMyGarden Kotlin -
Step3 67 : droidkaigi/step3 Move
() Kotlin -
Step4 object 69 Show Intention Actions
Show Intention Actions Opt + Enter Kotlin -
71 Step1 Step2-4 Page
( ) Step5 return value PageObject -
Step5 return 72 PageObject return Show
Intention Actions Opt + Enter Kotlin -
Step5 return 73 : droidkaigi/step5 return
type Kotlin -
74 Step1 Step2-4 Page
( ) Step5 return value PageObject -
: p MyGardenPage.assertPlanted() ( '!' #
& p "%$: droidkaigi/extra 78 Kotlin -
p Espresso Test Recorder PageObject
p Android Studio ( ) p Kotlin Move 79 Kotlin -
% * p #'&+ p Espresso p "!
: Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 80 Kotlin AndroidX AAC Kotlin AndroidX -
% 5'#UI13 * p View.9 p ;)"/(ID )+8,$
p 2 p 4!(-&7:<60 81 AAC AAC -
AAC ! p Room: p LiveData RxJava !
p Pager: p LivePagedListBuilderRxPagedListBuilder p WorkManager: 82 ArchTaskExecutor Executors. newFixedThreadPool() AAC -
AAC ! p Room: p LiveData RxJava !
p Pager: p LivePagedListBuilderRxPagedListBuilder p WorkManager: 83 ArchTaskExecutor Executors. newFixedThreadPool() AAC -
ArchTaskExecutor 84 p AAC p CountingTaskExecutorRule
androidx.arch.core:core-testing:2.0.0 AAC -
ArchTaskExecutor: 85 AAC @get:Rule val countingRule =
CountingTaskExecutorRule() @Test fun myTest() { onView(...).perform(...) // AAC countingRule..drainTasks(1, TimeUnit.MINUTES) onView(...).perform(...) ... } -
ArchTaskExecutor: G S 86 p TaskExecutorWithIdlingResourceRule p B /
. / AAC @get:Rule val executorRule = TaskExecutorWithIdlingResourceRule() Rule L: OK -
AAC ! p Room: p LiveData RxJava !
p Pager: p LivePagedListBuilderRxPagedListBuilder p WorkManager: 87 ArchTaskExecutor Executors. newFixedThreadPool() AAC -
ArchTaskExecutor : 88 ThreadPoolExecutor p WorkManager
import androidx.work.Configuration ... val executor = ... val configuration = Configuration.Builder() .setExecutor(executor) .build() WorkManager.initialize(context, configuration) AAC -
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 ) -
ArchTaskExecutor: " 90 (: CoroutineWorker) asCoroutineDispatcher()
class MyWorker(...): CoroutineWorker(...) { override val coroutineContext: CoroutineDispatcher get() { val executor = IdlingThreadPoolExecutor(...) return executor.asCoroutineDispatcher() } ... AAC CoroutineWorker ! -
p AAC(!%
'" p ArchTaskExecutor& p $#Executor& p Kotlin & 91 -
% * p #'&+ p Espresso p "!
: Android Sunflower p Espresso Test Recorder) p PageObject"" (, p AAC-$ (" p 92 Kotlin AndroidX AAC Kotlin AndroidX -
$# 93 p EspressoAndroidXKotlin )"*! p AndroidX) Recorder
OK p ,+ 'deprecated -& (AndroidJUnit4ActivityScenarioRule) p PageObject Kotlin (% -
! 94 p AAC Espresso% *"(
) p ' $&# -
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 -
"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