Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Coroutines Test 入門 / Android Test Night #8
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
star_zero
March 10, 2023
Programming
1.4k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Coroutines Test 入門 / Android Test Night #8
star_zero
March 10, 2023
More Decks by star_zero
See All by star_zero
今からはじめるAndroidアプリ開発 2024 / DevFest 2024
star_zero
0
1.6k
Jetpack Compose の Side-effect を使いこなす / DroidKaigi 2023
star_zero
5
7.2k
Android 14 新機能 / Android 14 Meetup Nagoya
star_zero
1
690
Android 14 と Predictive back gesture / Shibuya.apk #42
star_zero
0
500
What's new in Jetpack / I/O Extended Japan 2022
star_zero
1
720
Kotlin 2021 Recap / DevFest 2021
star_zero
3
1.4k
Kotlin Symbol Processing (KSP) を使ったコード生成 / DroidKaigi 2021
star_zero
2
5.3k
What's new Android 12
star_zero
0
630
これからはじめるAndroid開発 / DevFest 2020
star_zero
4
780
Other Decks in Programming
See All in Programming
Press start. Python's next generation.
willingc
PRO
3
130
freeeにおけるEvalsの実践例の紹介
freee
PRO
0
150
Go 1.27からのGODEBUG / Go 1.27 リリースパーティ #go127party
mazrean
0
220
不幸な GC
chencmd
0
740
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
580
Claude CodeとAgentCore Gatewayを繋ぐ際の認証認可 / Authentication and authorization when connecting Claude Code with AgentCore Gateway
har1101
2
380
Go 1.27 における memory allocation の高速化
andpad
0
320
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
2
440
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
560
ALB ログから Trace を気合で繋げる技術
fohte
5
530
夏だ!祭りだ!祭りとはドメインモデリングでは?
ryugen04
0
390
Webエンジニアなのにブラウザの仕組みがわからないので、Pythonで自作してみた
tatsuki12
4
1.1k
Featured
See All Featured
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
360
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Being A Developer After 40
akosma
91
590k
Optimising Largest Contentful Paint
csswizardry
37
3.9k
Embracing the Ebb and Flow
colly
88
5.1k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.1k
Thoughts on Productivity
jonyablonski
76
5.3k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.8k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
Designing for Timeless Needs
cassininazir
1
450
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
290
Transcript
Android Test Night #8 2023/03/10 Coroutines Test 入門
• Kenji Abe • @STAR_ZERO • Google Developers Expert for
Android, Kotlin • DeNA Co., Ltd.
// build.gradle dependencies { // ... testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4") }
supsend関数のテスト
class Sample { suspend fun run(): String { return "hoge"
} }
class SampleTest { @Test fun testRun() = runTest { val
sample = Sample() val result = sample.run() assert(result == "hoge") } }
class SampleTest { @Test fun testRun() = runTest { val
sample = Sample() val result = sample.run() assert(result == "hoge") } }
• runBlockingのようなもの • delay関数はすべてスキップされる ◦ Vertial Timeを制御することができる • TestScopeが使用される runTest
TestDispatchers
• StandardTestDispatcher ◦ runTestデフォルト ◦ TestCoroutineSchedulerを使用するシンプルなDispatcher • UnconfinedTestDispatcher ◦ Dispatchers.Unconfinedのようなもの
◦ トップレベルのlaunch/asyncがすぐに実行される TestDispatchers
class SampleTest { @Test fun testRun() = runTest { val
sample = Sample() val result = sample.run() assert(result == "hoge") } }
@Test fun test() = runTest { var result = 0
launch { result = 1 } assert(result == 1) }
@Test fun test() = runTest { var result = 0
launch { result = 1 } assert(result == 1) } ❌ Failed
@Test fun test() = runTest { var result = 0
launch { result = 1 } assert(result == 1) } ① ② ③
@Test fun test() = runTest { var result = 0
launch { result = 1 } runCurrent() assert(result == 1) } ✅ Success
@Test fun test() = runTest { var result = 0
launch { result = 1 } runCurrent() assert(result == 1) } ① ② ③ ④
@Test fun test() = runTest { var result = 0
launch { delay(1000) result = 1 } runCurrent() assert(result == 1) }
@Test fun test() = runTest { var result = 0
launch { delay(1000) result = 1 } runCurrent() assert(result == 1) } ❌ Failed
@Test fun test() = runTest { var result = 0
launch { delay(1000) result = 1 } runCurrent() assert(result == 1) } ① ② ③ ④ ⑤
@Test fun test() = runTest { // ... advanceUntilIdle() //
または advanceTimeBy(1001) assert(result == 1) } ✅ Success
@Test fun test() = runTest(UnconfinedTestDispatcher()) { var result = 0
launch { result = 1 } assert(result == 1) }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { var result = 0
launch { result = 1 } assert(result == 1) } ✅ Success
Mainスレッド対応
class Sample { suspend fun run(): String = withContext(Dispatchers.Main) {
"hoge" } }
@Test fun testRun() = runTest { val sample = Sample()
val result = sample.run() assert(result == "hoge") }
@Test fun testRun() = runTest { val sample = Sample()
val result = sample.run() assert(result == "hoge") }
@Before fun setUp() { Dispatchers.setMain(StandardTestDispatcher()) } @After fun tearDown() {
Dispatchers.resetMain() }
Flowのテスト
class Sample { val flow = MutableSharedFlow<Int>() suspend fun emit(value:
Int) { flow.emit(value) } }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { val sample = Sample()
val result = mutableListOf<Int>() val job = launch { sample.flow.toCollection(result) } assert(result.size == 0) sample.emit(1) assert(result.size == 1) assert(result.first() == 1) job.cancel() }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { val sample = Sample()
val result = mutableListOf<Int>() // ... }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { val sample = Sample()
val result = mutableListOf<Int>() val job = launch { sample.flow.toCollection(result) } // ... }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { val sample = Sample()
val result = mutableListOf<Int>() val job = launch { sample.flow.toCollection(result) } // ... }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { // ... val job
= launch { sample.flow.toCollection(result) } assert(result.size == 0) // ... }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { // ... val job
= launch { sample.flow.toCollection(result) } sample.emit(1) // ... }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { // ... sample.emit(1) assert(result.size
== 1) assert(result.first() == 1) job.cancel() }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { // ... val job
= launch { sample.flow.toCollection(result) } // ... job.cancel() }
@Test fun test() = runTest(UnconfinedTestDispatcher()) { // ... backgroundScope.launch {
sample.flow.toCollection(result) } // ... // job.cancel() }
Turbine (時間の都合上省略...) https://github.com/cashapp/turbine
まとめ
• runTest • StandardTestDispatcher / UnconfinedTestDispatcher • Dispatchers.setMain • backgroundScope
まとめ
ありがとうございました