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
FragmentScenarioとFragmentFactoryで楽しくUIテスト / Fr...
Search
tkmnzm
June 28, 2019
Programming
2.1k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
FragmentScenarioとFragmentFactoryで楽しくUIテスト / FragmentScenario x FragmentFactory UI Test
tkmnzm
June 28, 2019
More Decks by tkmnzm
See All by tkmnzm
AndroidアプリのUIバリエーションをあの手この手で確認する / Check UI variations of Android apps by various means
tkmnzm
1
1.6k
Androidアプリの良いユニットテストを考える / Thinking about good unit tests for Android apps
tkmnzm
5
10k
Google I:O 2023 Androidの自動テストアップデートまとめ / Google I:O 2023 Android Testing Update Recap
tkmnzm
0
690
コルーチンのエラーをテストするためのTips / Tips for testing Kotlin Coroutine errors
tkmnzm
0
1.3k
Androidのモダンな技術選択にあわせて自動テストも アップデートしよう / Update your automated tests to match Android's modern technology choices
tkmnzm
3
2.6k
SWET dev-vitalチームによるプロジェクトの健康状態可視化の取り組み / SWET dev-vital team's efforts to visualize the health of the project
tkmnzm
1
1.4k
モバイルアプリテスト入門 / Getting Started with Mobile App Testing
tkmnzm
1
630
25分で作るAndroid Lint / Android Lint made in 25 minutes
tkmnzm
0
1k
2年半ぶりのプロダクト開発であらためて感じた自動テストの大切さ / realized the importance of automatic testing with product development for the first time in two and a half years
tkmnzm
1
870
Other Decks in Programming
See All in Programming
気圧・高度・GPSを記録&可視化するアプリ「Koudo」を作った話
hjmkth
1
340
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
820
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
110
Contextとはなにか
chiroruxx
1
390
A2UI という光を覗いてみる
satohjohn
1
170
Creating Composable Callables in Contemporary C++
rollbear
0
180
吝嗇家のためのAI活用 / AI development for miser - ChatGPT + Issue Driven Development
tooppoo
0
160
Hatena Engineer Seminar #37「言語モデルの活用に関する研究」
slashnephy
0
460
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
4.8k
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.6k
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
1
170
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
290
Featured
See All Featured
The Art of Programming - Codeland 2020
erikaheidi
57
14k
Crafting Experiences
bethany
1
200
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
65
56k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.3k
How GitHub (no longer) Works
holman
316
150k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.9k
ラッコキーワード サービス紹介資料
rakko
1
3.8M
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Code Review Best Practice
trishagee
74
20k
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
400
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
230
Self-Hosted WebAssembly Runtime for Runtime-Neutral Checkpoint/Restore in Edge–Cloud Continuum
chikuwait
0
630
Transcript
FragmentSenarioͱ FragmentFactoryͰ ָ͘͠UIςετ DeNA, SWET Nozomi Takuma
ࣗݾհ Nozomi Takuma DeNAͷSWETάϧʔϓ Androidͱςετ͕͖
Outline FragmentScenario Usage FragmentFactory Usage FragmentScenario x FragmentFactory
UIςετ είʔϓ͕େ͖͘ͳΓ͗͢Δͱ ࣮࣮ߦେม ·ͣݱ࣮తʹςετΛӡ༻Ͱ͖Δ είʔϓΛઃఆ͍ͨ͠ͱ͜Ζ
Fragmentςετ είʔϓΛ୯ҰͷFragmentʹઃఆ͢Δ ґଘΛςετμϒϧʹ͢Δ͜ͱͰ ͞ΒʹείʔϓΛখ͘͞Ͱ͖Δ
είʔϓΛখ͘͞(ྫ) Fragment ViewModel Test Double
είʔϓΛখ͘͞(ྫ) Fragment ViewModel Test Double είʔϓ͜͜
ςετͰ͖Δ͜ͱ FragmentͷUIςετ Fragment ͱViewModelͷͭͳ͗͜Έ LiveDataͷObserveͱUIߋ৽ DataBindingͰͷ࿈ܞ
FragmentScenario Fragmentͷςετ༻API EspressoΛͬͨUIςετ Fragmentͷঢ়ଶΛίϯτϩʔϧ androidx.fragment.fragment-tesNng
FragmentScenario @Test fun test() { // FragmentΛAcNvityͷRootʹΞλονͯ͠ىಈ launchFragmentInContainer<MyFragment>() }
FragmentScenario @Test fun test() { launchFragmentInContainer<MyFragment>() // EspressoͰUIͷݕূ onView(withId(R.id.text_view)).check(matches(withText("Hello"))) }
FragmentScenario @Test fun test() { val scenario = launchFragmentInContainer<MyFragment>() //
Fragmentͷ࠶ੜ scenario.recreate() onView(withId(R.id.stored_text)).check(matches(withText("Stored"))) }
FragmentScenario @Test fun test() { val scenario = launchFragmentInContainer<MyFragment>() //
FragmentʹΞΫηε͍ͨ͠ͱ͖ scenario.onFragment { fragment -> fragment.clearText() } // EspressoͰͷૢ࡞onFragmentϒϩοΫʹॻ͔ͳ͍ onView(withId(R.id.text)).check(matches(withText(""))) }
FragmentScenario Doc Test your app’s fragments h]ps://developer.android.com/ training/basics/fragments/tesNng
ґଘΛΓ͍ͨ͠ DI Dagger x FragmentScenario? DI LibraryΛಋೖ͍ͯ͠ͳ͍ͱ͜Ζ͋Δ
ґଘΛΓ͍ͨ͠ launchFragmentInContainer(fragmentArgs: Bundle? = null, @StyleRes themeResId: Int = ..,
factory: FragmentFactory? = null)
launchFragmentInContainer(fragmentArgs: Bundle? = null, @StyleRes themeResId: Int = .., factory:
FragmentFactory? = null) FragmentFactory!!! ґଘΛΓ͍ͨ͠
FragmentFactory FragmentΠϯελϯεੜΛίϯτ ϩʔϧ ҙͷίϯετϥΫλΛ࣋ͭ FragmentΛੜ͢ΔΑ͏ઃఆͰ͖Δ androidx.fragment.fragment:1.1.0+
FragmentFactory class MyFragmentFactory() : FragmentFactory() { override fun instanNate(classLoader: ClassLoader,
className: String): Fragment { // classʹରͯ͠ͲͷFragmentΛੜ͢Δ͔Λ͜͜ʹॻ͍͍ͯ͘ if (className == MyFragment::class.java.name) { return MyFragment() } return super.instanNate(classLoader, className) } }
Custom Constructor class MyFragment(private val viewModelFactory: .. ) : Fragment()
{ private lateinit var viewModel: MyViewModel override fun onAcNvityCreated(savedInstanceState: Bundle?) { super.onAcNvityCreated(savedInstanceState) viewModel = ViewModelProviders.of(this, viewModelFactory).get(MyViewModel::class.java) } }
Custom Constructor class MyFragment(private val viewModelFactory: .. ) : Fragment()
{ private lateinit var viewModel: MyViewModel override fun onAcNvityCreated(savedInstanceState: Bundle?) { super.onAcNvityCreated(savedInstanceState) viewModel = ViewModelProviders.of(this, viewModelFactory).get(MyViewModel::class.java) } } ViewModelFactoryΛ ίϯετϥΫλͰड͚औΔFragment
Custom Constructor class MyFragmentFactory() : FragmentFactory() { override fun instanNate(classLoader:
ClassLoader, className: String): Fragment { if (className == MyFragment::class.java.name) { // ґଘΛίϯετϥΫλͰͯ͠Fragment Λੜ val viewModelFactory = MyViewModelFactory(MyDataSource()) return MyFragment(viewModelFactory) } return super.instanNate(classLoader, className) } }
FragmentFactoryΛ͏ FragmentManager#setFragmentFactory ઃఆͨ͠FragmentFactoryΛͬͯ FragmentͷੜΛͯ͘͠ΕΔ androidx.appcompat:appcompat:1.1.0+
FragmentFactoryΛ͏ class MyAcNvity : AppCompatAcNvity() { override fun onCreate(savedInstanceState: Bundle?)
{ super.onCreate(savedInstanceState) // setContentViewͷલʹFragmentFactoryΛઃఆ͢Δ // AcNvity͔ΒFragmentFactoryܦ༝ͰґଘΛ͢ͷՄ supportFragmentManager.fragmentFactory = MyFragmentFactory(applicaNon) setContentView(R.layout.acNvity_my) } }
with NavigaNon FragmentManagerʹFragmentFactoryΛ ઃఆ͍ͯ͠ΕɺNavigaNonભҠ࣌ ઃఆͨ͠FragmentFactory͕ΘΕΔ
with Dagger(ࢀߟURL) h]ps://satoshun.github.io/2018/11/ android_all_inject_ctor/ h]ps://github.com/satoshun-android- example/ConstructorInjecNonExample
FragmentFactory x UIςετ @Test fun test() { launchFragmentInContainer<MyFragment>(factory = object
: FragmentFactory() { override fun instanNate(classLoader: ClassLoader, className: String): Fragment { val viewModelFactory = ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), TestDataSource()) return MyFragment(viewModelFactory) } }) } FragmentFactory x UIςετ
FragmentFactory x UIςετ @Test fun test() { launchFragmentInContainer<MyFragment>(factory = object
: FragmentFactory() { override fun instanNate(classLoader: ClassLoader, className: String): Fragment { val viewModelFactory = ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), TestDataSource()) return MyFragment(viewModelFactory) } }) } FragmentFactory x UIςετ Ұ෦Λελϒʹஔ͖͑
FragmentFactory x UIςετ Fragment ViewModel Test Double Ͱ͖ͨ
FragmentFactory x UIςετ @Test fun test() { launchFragmentInContainer<MyFragment>(factory = object
: FragmentFactory() { override fun instanNate(classLoader: ClassLoader, className: String): Fragment { val viewModelFactory = ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), TestDataSource()) return MyFragment(viewModelFactory) } }) } FragmentFactory x UIςετ ͬ͞͞ͱґଘΛίϯτϩʔϧͰ͖ͯ ͨͷ͍͠
Summary FragmentScenarioͱFragmentFactoryΛ ͑είʔϓΛݶఆͨ͠UIςετΛ ൺֱత؆୯ʹ࣮Ͱ͖Δ
͝ਗ਼ௌ͋Γ͕ͱ͏ ͍͟͝·ͨ͠ʂ