$30 off During Our Annual Pro Sale. View Details »

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

tkmnzm
June 28, 2019

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

tkmnzm

June 28, 2019
Tweet

More Decks by tkmnzm

Other Decks in Programming

Transcript

  1. FragmentSenarioͱ
    FragmentFactoryͰ

    ָ͘͠UIςετ
    DeNA, SWET Nozomi Takuma

    View Slide

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

    View Slide

  3. Outline
    FragmentScenario Usage
    FragmentFactory Usage
    FragmentScenario x FragmentFactory

    View Slide

  4. UIςετ
    είʔϓ͕େ͖͘ͳΓ͗͢Δͱ

    ࣮૷΋࣮ߦ΋େม
    ·ͣ͸ݱ࣮తʹςετΛӡ༻Ͱ͖Δ

    είʔϓΛઃఆ͍ͨ͠ͱ͜Ζ

    View Slide

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

    ͞ΒʹείʔϓΛখ͘͞΋Ͱ͖Δ

    View Slide

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

    Double

    View Slide

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

    Double
    είʔϓ͸͜͜

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  13. FragmentScenario
    @Test
    fun test() {
    val scenario = launchFragmentInContainer()
    // FragmentʹΞΫηε͍ͨ͠ͱ͖
    scenario.onFragment { fragment ->
    fragment.clearText()
    }
    // EspressoͰͷૢ࡞͸onFragmentϒϩοΫ಺ʹ͸ॻ͔ͳ͍
    onView(withId(R.id.text)).check(matches(withText("")))
    }

    View Slide

  14. FragmentScenario Doc
    Test your app’s fragments
    h]ps://developer.android.com/
    training/basics/fragments/tesNng

    View Slide

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

    View Slide

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

    View Slide

  17. launchFragmentInContainer(fragmentArgs: Bundle? = null,
    @StyleRes themeResId: Int = ..,
    factory: FragmentFactory? = null)
    FragmentFactory!!!
    ґଘΛ੾Γ཭͍ͨ͠

    View Slide

  18. FragmentFactory
    FragmentΠϯελϯεੜ੒Λίϯτ
    ϩʔϧ
    ೚ҙͷίϯετϥΫλΛ࣋ͭ
    FragmentΛੜ੒͢ΔΑ͏ઃఆͰ͖Δ
    androidx.fragment.fragment:1.1.0+

    View Slide

  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)
    }
    }

    View Slide

  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)
    }
    }

    View Slide

  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

    View Slide

  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)
    }
    }

    View Slide

  23. FragmentFactoryΛ࢖͏
    FragmentManager#setFragmentFactory
    ઃఆͨ͠FragmentFactoryΛ࢖ͬͯ
    Fragmentͷੜ੒Λͯ͘͠ΕΔ
    androidx.appcompat:appcompat:1.1.0+

    View Slide

  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)
    }
    }

    View Slide

  25. with NavigaNon
    FragmentManagerʹFragmentFactoryΛ

    ઃఆ͍ͯ͠Ε͹ɺNavigaNonભҠ࣌΋

    ઃఆͨ͠FragmentFactory͕࢖ΘΕΔ

    View Slide

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

    View Slide

  27. FragmentFactory x UIςετ
    @Test
    fun test() {
    launchFragmentInContainer(factory = object : FragmentFactory() {

    override fun instanNate(classLoader: ClassLoader, className: String): Fragment {
    val viewModelFactory = 

    ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), 

    TestDataSource())
    return MyFragment(viewModelFactory)
    }
    })
    }
    FragmentFactory x UIςετ

    View Slide

  28. FragmentFactory x UIςετ
    @Test
    fun test() {
    launchFragmentInContainer(factory = object : FragmentFactory() {

    override fun instanNate(classLoader: ClassLoader, className: String): Fragment {
    val viewModelFactory = 

    ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), 

    TestDataSource())
    return MyFragment(viewModelFactory)
    }
    })
    }
    FragmentFactory x UIςετ
    Ұ෦Λελϒʹஔ͖׵͑

    View Slide

  29. FragmentFactory x UIςετ
    Fragment ViewModel
    Test

    Double
    Ͱ͖ͨ

    View Slide

  30. FragmentFactory x UIςετ
    @Test
    fun test() {
    launchFragmentInContainer(factory = object : FragmentFactory() {

    override fun instanNate(classLoader: ClassLoader, className: String): Fragment {
    val viewModelFactory = 

    ViewModelFactory(ApplicaNonProvider.getApplicaNonContext(), 

    TestDataSource())
    return MyFragment(viewModelFactory)
    }
    })
    }
    FragmentFactory x UIςετ
    ͬ͞͞ͱґଘΛίϯτϩʔϧͰ͖ͯ

    ͨͷ͍͠

    View Slide

  31. Summary
    FragmentScenarioͱFragmentFactoryΛ

    ࢖͑͹είʔϓΛݶఆͨ͠UIςετΛ

    ൺֱత؆୯ʹ࣮૷Ͱ͖Δ

    View Slide

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

    View Slide