FragmentScenarioとFragmentFactoryで楽しくUIテスト / FragmentScenario x FragmentFactory UI Test

7867fe52a9be4257508a516d4df61578?s=47 tkmnzm
June 28, 2019

FragmentScenarioとFragmentFactoryで楽しくUIテスト / FragmentScenario x FragmentFactory UI Test

7867fe52a9be4257508a516d4df61578?s=128

tkmnzm

June 28, 2019
Tweet

Transcript

  1. FragmentSenarioͱ FragmentFactoryͰ
 ָ͘͠UIςετ DeNA, SWET Nozomi Takuma

  2. ࣗݾ঺հ Nozomi Takuma DeNAͷSWETάϧʔϓ Androidͱςετ͕޷͖

  3. Outline FragmentScenario Usage FragmentFactory Usage FragmentScenario x FragmentFactory

  4. UIςετ είʔϓ͕େ͖͘ͳΓ͗͢Δͱ
 ࣮૷΋࣮ߦ΋େม ·ͣ͸ݱ࣮తʹςετΛӡ༻Ͱ͖Δ
 είʔϓΛઃఆ͍ͨ͠ͱ͜Ζ

  5. Fragmentςετ είʔϓΛ୯ҰͷFragmentʹઃఆ͢Δ ґଘΛςετμϒϧʹ͢Δ͜ͱͰ
 ͞ΒʹείʔϓΛখ͘͞΋Ͱ͖Δ

  6. είʔϓΛখ͘͞(ྫ) Fragment ViewModel Test
 Double

  7. είʔϓΛখ͘͞(ྫ) Fragment ViewModel Test
 Double είʔϓ͸͜͜

  8. ςετͰ͖Δ͜ͱ FragmentͷUIςετ Fragment ͱViewModelͷͭͳ͗͜Έ LiveDataͷObserveͱUIߋ৽ DataBindingͰͷ࿈ܞ

  9. FragmentScenario Fragmentͷςετ༻API EspressoΛ࢖ͬͨUIςετ Fragmentͷঢ়ଶΛίϯτϩʔϧ androidx.fragment.fragment-tesNng

  10. FragmentScenario @Test fun test() { // FragmentΛAcNvityͷRootʹΞλονͯ͠ىಈ launchFragmentInContainer<MyFragment>() }

  11. FragmentScenario @Test fun test() { launchFragmentInContainer<MyFragment>() // EspressoͰUIͷݕূ onView(withId(R.id.text_view)).check(matches(withText("Hello"))) }

  12. FragmentScenario @Test fun test() { val scenario = launchFragmentInContainer<MyFragment>() //

    Fragmentͷ࠶ੜ੒ scenario.recreate() onView(withId(R.id.stored_text)).check(matches(withText("Stored"))) }
  13. FragmentScenario @Test fun test() { val scenario = launchFragmentInContainer<MyFragment>() //

    FragmentʹΞΫηε͍ͨ͠ͱ͖ scenario.onFragment { fragment -> fragment.clearText() } // EspressoͰͷૢ࡞͸onFragmentϒϩοΫ಺ʹ͸ॻ͔ͳ͍ onView(withId(R.id.text)).check(matches(withText(""))) }
  14. FragmentScenario Doc Test your app’s fragments h]ps://developer.android.com/ training/basics/fragments/tesNng

  15. ґଘΛ੾Γ཭͍ͨ͠ DI Dagger x FragmentScenario? DI LibraryΛಋೖ͍ͯ͠ͳ͍ͱ͜Ζ΋͋Δ

  16. ґଘΛ੾Γ཭͍ͨ͠ launchFragmentInContainer(fragmentArgs: Bundle? = null, @StyleRes themeResId: Int = ..,

    factory: FragmentFactory? = null)
  17. launchFragmentInContainer(fragmentArgs: Bundle? = null, @StyleRes themeResId: Int = .., factory:

    FragmentFactory? = null) FragmentFactory!!! ґଘΛ੾Γ཭͍ͨ͠
  18. FragmentFactory FragmentΠϯελϯεੜ੒Λίϯτ ϩʔϧ ೚ҙͷίϯετϥΫλΛ࣋ͭ FragmentΛੜ੒͢ΔΑ͏ઃఆͰ͖Δ androidx.fragment.fragment:1.1.0+

  19. 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) } }
  20. 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) } }
  21. 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
  22. 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) } }
  23. FragmentFactoryΛ࢖͏ FragmentManager#setFragmentFactory ઃఆͨ͠FragmentFactoryΛ࢖ͬͯ Fragmentͷੜ੒Λͯ͘͠ΕΔ androidx.appcompat:appcompat:1.1.0+

  24. 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) } }
  25. with NavigaNon FragmentManagerʹFragmentFactoryΛ
 ઃఆ͍ͯ͠Ε͹ɺNavigaNonભҠ࣌΋
 ઃఆͨ͠FragmentFactory͕࢖ΘΕΔ

  26. with Dagger(ࢀߟURL) h]ps://satoshun.github.io/2018/11/ android_all_inject_ctor/ h]ps://github.com/satoshun-android- example/ConstructorInjecNonExample

  27. 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ςετ
  28. 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ςετ Ұ෦Λελϒʹஔ͖׵͑
  29. FragmentFactory x UIςετ Fragment ViewModel Test
 Double Ͱ͖ͨ

  30. 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ςετ ͬ͞͞ͱґଘΛίϯτϩʔϧͰ͖ͯ
 ͨͷ͍͠
  31. Summary FragmentScenarioͱFragmentFactoryΛ
 ࢖͑͹είʔϓΛݶఆͨ͠UIςετΛ
 ൺֱత؆୯ʹ࣮૷Ͱ͖Δ

  32. ͝ਗ਼ௌ͋Γ͕ͱ͏ ͍͟͝·ͨ͠ʂ