6
unit and integration tests
All tested!
unit and integration tests
unit and integration tests
unit and integration tests
unit and integration tests
Slide 7
Slide 7 text
7
First implementation
Slide 8
Slide 8 text
8
2h later…
Slide 9
Slide 9 text
9
Finally!
Slide 10
Slide 10 text
10
Main question
Is it ridable?
Slide 11
Slide 11 text
11
Check the junctions
Slide 12
Slide 12 text
12
Expected result — bike can ride
Slide 13
Slide 13 text
13
Road
Slide 14
Slide 14 text
14
com.bike.app
Slide 15
Slide 15 text
15
What if bicycle has been broken?
Slide 16
Slide 16 text
16
Call to repair
Slide 17
Slide 17 text
17
Hand it over to the repair
Slide 18
Slide 18 text
18
Wait
Slide 19
Slide 19 text
19
Each bug takes a long time
Slide 20
Slide 20 text
20
Mobile: Bug found
1. Fix/open PR, wait for the review, merge
Slide 21
Slide 21 text
21
Mobile: Bug found
1. Fix/open PR, wait for the review, merge
2. Test it
Slide 22
Slide 22 text
22
Mobile: Bug found
1. Fix/open PR, wait for the review, merge
2. Test it
3. Upload to the Google play
Slide 23
Slide 23 text
23
Mobile: Bug found
1. Fix/open PR, wait for the review, merge
2. Test it
3. Upload to the Google play
4. Wait for Google play review…
Slide 24
Slide 24 text
24
Mobile: Bug found
1. Fix/open PR, wait for the review, merge
2. Test it
3. Upload to the Google play
4. Wait for Google play review…
5. Wait for rolling out
Slide 25
Slide 25 text
25
Mobile: Bug found
1. Fix/open PR, wait for the review, merge
2. Test it
3. Upload to the Google play
4. Wait for Google play review…
5. Wait for rolling out
6. Wait for the users to download it
Slide 26
Slide 26 text
26
What affects quality?
Slide 27
Slide 27 text
27
What affects quality?
1. More engineers == More features
Slide 28
Slide 28 text
28
What affects quality?
1. More engineers == More features
2. Release frequency
Slide 29
Slide 29 text
29
UI testing — our need
Slide 30
Slide 30 text
30
UI testing — complicated
Slide 31
Slide 31 text
31
Slide 32
Slide 32 text
32
Writing
Espresso UiAutomator
Google provided
Community
KAutomator
Kakao
Kaspresso
Slide 33
Slide 33 text
33
Writing
Running
AndroidJUnitRunner
Orchestrator
Google provided
Espresso UiAutomator
Google provided
Community
KAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Community
Flank
Slide 34
Slide 34 text
34
Writing Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Community
Whereto run
Emulator
Real device
Docker container
Real network
Mock
network
Device
Device condition
Slide 35
Slide 35 text
35
Writing
Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Community
Whereto run
Emulator
Real device
Docker container
Device
Real network
Mock network
Device condition
Infrastructure
Cloud
Own Server
Firebase GCloud
Amazon
Kubernetes
Slide 36
Slide 36 text
36
Writing
Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Community
Whereto run
Emulator
Real device
Docker container
Device
Real network
Mock network
Device condition
Infrastructure
Cloud
Own Server
Firebase GCloud
Amazon
Kubernetes
Cloud
Processes
CI/CD
Release
pipeline
Validation on
PR
When to write?
Slide 37
Slide 37 text
37
Writing
Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Community
Whereto run
Emulator
Real device
Docker container
Device
Real network
Mock network
Device condition
Infrastructure
Cloud
Own Server
Firebase GCloud
Amazon
Kubernetes
Cloud
Processes
CI/CD
Release
Validation on PR
When to write?
Analytics
Test report Allure
In
fl
ux db Grafana
Found bugs dynamics
Slide 38
Slide 38 text
38
Writing
Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Community
Whereto run
Emulator
Real device
Docker container
Device
Real network
Mock network
Device condition
Infrastructure
Cloud
Own Server
Firebase GCloud
Amazon
Kubernetes
Cloud
Processes
CI/CD
Release
Validation on PR
When to write?
Analytics
Test report Allure
In
fl
ux db Grafana
Found bugs dynamics
Slide 39
Slide 39 text
39
Writing
Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Community
Whereto run
Emulator
Real device
Docker container
Device
Real network
Mock network
Device condition
Infrastructure
Own Server
Firebase GCloud
Amazon
Kubernetes
Processes
CI/CD
Release
Validation on PR
When to write?
Analytics
Test report Allure
In
fl
ux db Grafana
Found bugs dynamics
Cloud
Should work ne
Slide 40
Slide 40 text
40
Writing
Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KUiAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Whereto run
Emulator
Real device
Docker container
Device
Real network
Mock network
Device condition
Infrastructure
Cloud
Own Server
Firebase GCloud
Amazon
Kubernetes
Cloud
Processes
CI/CD
Release
Validation on PR
When to write?
Analytics
Test report Allure
In
fl
ux db Grafana
Found bugs dynamics
This talk about
Slide 41
Slide 41 text
41
Writing
Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KUiAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Whereto run
Emulator
Real device
Docker container
Device
Real network
Mock network
Device condition
Infrastructure
Cloud
Own Server
Firebase GCloud
Amazon
Kubernetes
Cloud
Processes
CI/CD
Release
Validation on PR
When to write?
Analytics
Test report Allure
In
fl
ux db Grafana
Found bugs dynamics
This talk about
Slide 42
Slide 42 text
42
Writing
Running
AndroidJUnitRunner
Orchestrator
Espresso UiAutomator
Google provided
Community
KUiAutomator
Kakao
Kaspresso
Spoon
Marathon
AvitoRunner
Composer Fork
Flank
Google provided
Whereto run
Emulator
Real device
Docker container
Device
Real network
Mock network
Device condition
Infrastructure
Cloud
Own Server
Firebase GCloud
Amazon
Kubernetes
Cloud
Processes
CI/CD
Release
Validation on PR
When to write?
Analytics
Test report Allure
In
fl
ux db Grafana
Found bugs dynamics
This talk about
67
Clearing
1. Within process
2. Clear package data
Slide 68
Slide 68 text
68
Within process clearing
1. LogoutComponent from the code
@Before
fun setUp() {
DI.provideLogoutInteractor().logout()
}
Slide 69
Slide 69 text
69
It’s bottleneck
@Before
fun setUp() {
DI.provideLogoutInteractor().logout()
}
May be broken
Slide 70
Slide 70 text
70
All tests will be failed
¯\_(ツ)_/¯
Slide 71
Slide 71 text
71
Within process clearing
1. LogoutComponent from the code
2. Internal storage clearing
Slide 72
Slide 72 text
72
Internal storage clearing
All db saved: /data/data/packagename/databases/
Slide 73
Slide 73 text
73
Internal storage clearing
All db saved: /data/data/packagename/databases/
@get:Rule
val clearDatabasesRule = ClearDatabasesRule()
@get:Rule
val clearFilesRule = ClearFilesRule()
@get:Rule
val clearPreferencesRule = ClearPreferencesRule()
Slide 74
Slide 74 text
74
Internal storage clearing
All db saved: /data/data/packagename/databases/
@get:Rule
val clearDatabasesRule = ClearDatabasesRule()
@get:Rule
val clearFilesRule = ClearFilesRule()
@get:Rule
val clearPreferencesRule = ClearPreferencesRule()
https://github.com/AdevintaSpain/Barista
Slide 75
Slide 75 text
75
It doesn’t solve all issues
!
Slide 76
Slide 76 text
76
It doesn’t solve all issues
1. You may have Runtime cache
Slide 77
Slide 77 text
77
It doesn’t solve all issues
1. You may have Runtime cache
2. App/Test process may be crashed
¯\_(ツ)_/¯
Slide 78
Slide 78 text
78
Within process: Conclusions
+ Fast implementation
+ Fast execution
Slide 79
Slide 79 text
79
Within process: Conclusions
- Bottleneck
- Don’t have any guarantee about clearing
- App/Test process might be crashed
+ Fast implementation
+ Fast execution
Slide 80
Slide 80 text
80
Clear package data
Slide 81
Slide 81 text
81
Idea
Slide 82
Slide 82 text
82
First thought
adb shell am instrument -w -m -e debug false -e class
‘….ExampleInstrumentedTest#test1,….ExampleInstrumentedTest#tes
t2’ com.alexbykov.myapplication.test/
androidx.test.runner.AndroidJUnitRunner
Slide 83
Slide 83 text
83
Launch rst test
adb shell am instrument …. ExampleInstrumentedTest#test1
119
3. Tooling
1. Impossible to validate flakiness
Slide 120
Slide 120 text
120
3. Tooling
1. Impossible to validate flakiness
2. Poor test report
Slide 121
Slide 121 text
121
AndroidJUnitRunner
Can’t help us with that
Slide 122
Slide 122 text
122
4. Choose: Test runner
Slide 123
Slide 123 text
123
Flakiness protection levels
Test code
Slide 124
Slide 124 text
124
Example1: Kaspresso
fun invokeFlakySafely(
params: FlakySafetyParams,
failureMessage: String? = null,
action: () -> T
): T {
var cachedError: Throwable
val startTime = System.currentTimeMillis()
do {
try {
return action.invoke()
} catch (error: Throwable) {
if (error.isAllowed(params.allowedExceptions)) {
cachedError = error
lock.withLock {
Timer().schedule(params.intervalMs) {
lock.withLock { condition.signalAll() }
}
condition.await()
}
} else {
throw error
}
}
} while (System.currentTimeMillis() - startTime <= params.timeoutMs)
throw cachedError.withMessage(failureMessage)
}
Slide 125
Slide 125 text
125
fun invokeFlakySafely(
params: FlakySafetyParams,
failureMessage: String? = null,
action: () -> T
): T {
var cachedError: Throwable
val startTime = System.currentTimeMillis()
do {
try {
return action.invoke()
} catch (error: Throwable) {
…
}
} while (System.currentTimeMillis() - startTime <= params.timeoutMs)
throw cachedError.withMessage(failureMessage)
}
Trying execute actions
Slide 126
Slide 126 text
126
fun invokeFlakySafely(
params: FlakySafetyParams,
failureMessage: String? = null,
action: () -> T
): T {
var cachedError: Throwable
val startTime = System.currentTimeMillis()
do {
try {
return action.invoke()
} catch (error: Throwable) {
…
}
} while (System.currentTimeMillis() - startTime <= params.timeoutMs)
throw cachedError.withMessage(failureMessage)
}
In a loop
Slide 127
Slide 127 text
127
Example2: Noti cation
Slide 128
Slide 128 text
128
Example2: Noti cation
class CloseNotificationsRule : ExternalResource() {
override fun before() {
UiDevice
.getInstance(InstrumentationRegistry.getInstrumentation())
.pressHome()
}
}
Slide 129
Slide 129 text
129
Example2: Noti cation
class CloseNotificationsRule : ExternalResource() {
override fun before() {
UiDevice
.getInstance(InstrumentationRegistry.getInstrumentation())
.pressHome()
}
}
@get:Rule
val closeNotification = CloseNotificationsRule()
Slide 130
Slide 130 text
130
Flakiness protection levels
Test code
Slide 131
Slide 131 text
131
Flakiness protection levels
Test code
Device
Slide 132
Slide 132 text
132
Example: Disabling animations
adb shell "settings put global window_animation_scale 0.0"
adb shell "settings put global transition_animation_scale 0.0"
adb shell "settings put global animator_duration_scale 0.0"
Slide 133
Slide 133 text
133
Example: Other
adb shell "settings put global window_animation_scale 0.0"
adb shell "settings put global transition_animation_scale 0.0"
adb shell "settings put global animator_duration_scale 0.0"
adb shell "settings put system screen_off_timeout 2147483647"
adb shell "settings put secure long_press_timeout 1500"
Slide 134
Slide 134 text
134
Flakiness protection levels
Test code
Device
Slide 135
Slide 135 text
135
Flakiness protection levels
Test code
Device
Test Runner
Slide 136
Slide 136 text
136
Test runner — last layer of flakiness
protection
ONE OF THE GOALS
Slide 137
Slide 137 text
137
Open source test runners
Marathon
Avito Runner
Spoon
Fork
Composer
Flank
Slide 138
Slide 138 text
138
Open source test runners
Marathon
Avito Runner
Spoon
Fork
Composer
Deprecated
Flank
Slide 139
Slide 139 text
139
Marathon vision
Just connect Devices to adb,
I’ll do the job
https://github.com/MarathonLabs/marathon
147
Idea: Flakiness strategy
— Calculate probability of passing
— Launch flakiness test in parallel before it’s failed
Slide 148
Slide 148 text
148
Flakiness strategy
Test1: Flaky in 50% //0.5 — probability of passing
Slide 149
Slide 149 text
149
Flakiness strategy
Test1: Flaky in 50% //0.5 — probability of passing
We want minimum: 80% //0.8 — probability of passing
Slide 150
Slide 150 text
150
Flakiness strategy
Test1: Flaky in 50% //0.5 — probability of passing
We want minimum: 80% //0.8 — probability of passing
Max parallel run: 3 //because more can affect speed of run
Slide 151
Slide 151 text
151
Probability
0.5 = 0.125
Test1: Flaky in 50%
We want minimum: 80%
Max parallel run: 3
//probability of all failed
3
Slide 152
Slide 152 text
152
Probability
0.5 = 0.125
1 - 0.125 = 0.875 > 0.8
Test1: Flaky in 50%
We want minimum: 80%
Max parallel run: 3
//probability of all failed
//Test will be executed 3 times in parallel
3
Slide 153
Slide 153 text
153
Flaky test (50% —> 80%)
Test
Test
Test
Slide 154
Slide 154 text
154
analyticsConfiguration:
graphite:
host: "influx.svc.cluster.local"
port: "8080"
prefix: "prf"
To make it work
Slide 155
Slide 155 text
155
Marathon
+ Retries
+ Flakiness strategy
Slide 156
Slide 156 text
156
Marathon
+ Retries
+ Flakiness strategy
+ Good report and allure support
Slide 157
Slide 157 text
157
Slide 158
Slide 158 text
158
Failed tests: Video/Logs
Slide 159
Slide 159 text
159
However default report doesn’t
support retries
Slide 160
Slide 160 text
160
But we can do that via Allure
allure generate report marathon_output/allure-results -o marathon_output/
allure-report --clean
Slide 161
Slide 161 text
161
Allure retries
Slide 162
Slide 162 text
162
Marathon
+ Retries
+ Flakiness strategy
+ Good report and allure support
Slide 163
Slide 163 text
163
Marathon
+ Retries
+ Flakiness strategy
+ Good report and allure support
+ Isolated environment
applicationPmClear: true
testApplicationPmClear: true
Slide 164
Slide 164 text
164
Marathon
+ Retries
+ Flakiness strategy
+ Good report and allure support
+ Isolated environment
+ ADB replacement
Slide 165
Slide 165 text
165
Replace ADB?
WAT?
Slide 166
Slide 166 text
166
Where do we use ADB?
Slide 167
Slide 167 text
167
ADB in instrumented tests
Install apps
Clearing
Pulling files
Record video
Slide 168
Slide 168 text
168
Problem
Most of the commands create
a new thread under the hood
Slide 169
Slide 169 text
169
Slide 170
Slide 170 text
170
Solution: ADAM
Slide 171
Slide 171 text
171
Solution: ADAM
Uses Kotlin coroutines under the hood
Slide 172
Slide 172 text
172
Adam vs ADB
ADB: 300 tests
T: 32 min
I/O: 22%
CPU: 48%
Adam: 300 tests
T: 26 min
I/O: 19%
CPU: 47 %
Slide 173
Slide 173 text
173
Marathon
+ Retries
+ Flakiness strategy
+ Good report and allure support
+ Isolated environment
+ ADB replacement
Slide 174
Slide 174 text
174
Marathon
+ Retries
+ Flakiness strategy
+ Good report and allure support
+ Isolated environment
+ ADB replacement
+ Flakiness validation
strictMode: true
shardingStrategy:
type: "count"
count: 100
Slide 175
Slide 175 text
175
Marathon
+ Retries
+ Flakiness strategy
+ Good report and allure support
+ Isolated environment
+ ADB replacement
+ Flakiness validation
+ Cross platform (iOS support)
Slide 176
Slide 176 text
176
Open source test runners
Marathon
Slide 177
Slide 177 text
177
Open source test runners
Marathon
Avito Runner
Slide 178
Slide 178 text
178
Avito runner vision
Just connect Kubernetes to me,
I’ll do the job
https://avito-tech.github.io/avito-android/test_runner/TestRunner/
Slide 179
Slide 179 text
179
Test Run: Finished
Test Run
Test Run 2
Slide 180
Slide 180 text
180
Connect all emulators to 2
Test Run 2
Slide 181
Slide 181 text
181
Marathon
Possible, but you need
to connect devices to adb by yourself
Autoscalling
Slide 182
Slide 182 text
182
Device farm
Slide 183
Slide 183 text
183
Device state
idle
busy
Device farm
Slide 184
Slide 184 text
184
Build agent
Slide 185
Slide 185 text
185
ADB connect
Build agent
Device farm
Slide 186
Slide 186 text
186
Avito runner
I’ll do it for you!
Autoscalling
Slide 187
Slide 187 text
187
Difference
Marathon
Avito Test Runner
- Auto-scalling
- Adam
- Flakiness strategy
- CLI
- Doesn’t support iOS
Slide 188
Slide 188 text
188
Difference
Marathon
Avito Test Runner
- Auto-scalling
- Adam
- Flakiness strategy
- CLI
- Doesn’t support iOS
- It’s not ready for open source
Slide 189
Slide 189 text
189
Open source test runners
Marathon
Avito Runner
Slide 190
Slide 190 text
190
Open source test runners
Marathon
Avito Runner
Flank
Slide 191
Slide 191 text
191
Flank vision
https://flank.github.io/flank/
I’ll make your life easier to
work with Firebase Test Lab
https://firebase.google.com/products/test-lab
Slide 192
Slide 192 text
192
Flank
+ Don’t need to care about where to run
— Firebase Test Lab — paid service
+ Crossplatform
Slide 193
Slide 193 text
193
Which one do I need to choose?
Slide 194
Slide 194 text
194
It depends :)
Slide 195
Slide 195 text
195
It depends :)
Product?
Team size? Company?
Scalability?
How often do you need to run?
How many tests do you have?
How often your codebase changed?
Slide 196
Slide 196 text
196
That’s on you
Marathon, Avito Runner:
+ invest your time to build infrastructure
+ invest your time to support
Slide 197
Slide 197 text
197
That’s on you
Marathon, Avito Runner:
+ invest your time to support
+ invest your time to build infrastructure
Flank + Firebase test lab:
+ You have to pay always
Slide 198
Slide 198 text
198
Marathon — the most powerful
Slide 199
Slide 199 text
199
Marathon — the most powerful
For any team.
Slide 200
Slide 200 text
200
Real device vs Emulator
Slide 201
Slide 201 text
201
Real device
Slide 202
Slide 202 text
202
Real device
+ Real condition
Slide 203
Slide 203 text
203
Real device
+ Real condition
+ Doesn’t consume CI resources
Slide 204
Slide 204 text
204
Real device
+ Real condition
+ Doesn’t consume CI resources
— Room with special condition
Slide 205
Slide 205 text
205
Real device
+ Real condition
+ Doesn’t consume CI resources
— Room with special condition
— Breaks often
281
Solutions
Wiremock
OkReplay
+ Readable report
+ Interceptor-based solution
— Lack of indexing
— Constant execution time per each request
Slide 282
Slide 282 text
282
Solutions
Wiremock
OkReplay
+ Readable report
+ Interceptor-based solution
— Lack of indexing
— Constant execution time per each request
— Abandoned :(
Slide 283
Slide 283 text
283
We’re implementing
our own open-source
solution for it
Slide 284
Slide 284 text
284
Network: Conclusion
— Mocked/Stubbed network it — the only way to have stable UI tests
Slide 285
Slide 285 text
285
Network: Conclusion
— Mocked/Stubbed network it — the only way to have stable UI tests
— Small project: MockWebServer
Slide 286
Slide 286 text
286
Network: Conclusion
— Mocked/Stubbed network it — the only way to have stable UI tests
— Small project: MockWebServer
— Have a lot of requests to mock? — OkReplay
Slide 287
Slide 287 text
287
Network: Conclusion
— Mocked/Stubbed network it — the only way to have stable UI tests
— Small project: MockWebServer
— Have a lot of requests to mock? — OkReplay
— Didn’t use OkHttp? — Wiremock
Slide 288
Slide 288 text
288
Conclusions
Slide 289
Slide 289 text
289
Android UI testing
Slide 290
Slide 290 text
290
Android UI testing
Expectations
Reality
Slide 291
Slide 291 text
291
Before you get started
Do not even start if you want to try it just for fun
Slide 292
Slide 292 text
292
Before you get started
Do not even start if you want to try it just for fun
You should have clear goal
Slide 293
Slide 293 text
293
Before you get started
You should have clear goal
Which solves real problems
Do not even start if you want to try it just for fun
Slide 294
Slide 294 text
294
UI testing blog
https://github.com/android-ui-testing/Cookbook/
Slide 295
Slide 295 text
295
Thanks to
Eugene Matsyuk
Alexey Tvorogov Dmitriy Voronin Anton Malinskiy
Dmitry Movchan
Kaspresso adb server Kaspresso creator Marathon creator
Avito runner creator Kaspresso adb server
& a lot of researches