Upgrade to Pro — share decks privately, control downloads, hide ads and more …

古典部 開発合宿発表スライド

古典部 開発合宿発表スライド

今回はAndroidのTestがんばるぞい

Rei Matsushita

August 13, 2016
Tweet

More Decks by Rei Matsushita

Other Decks in Technology

Transcript

  1. ςΩετ ΞϓϦͷઃܭͷ࿩ ▸ ࢖༻ޙ Presenter View Activity / Fragment XML

    Infra Model API Preferences Repository Service Entity DDDͬΆ͍Something ΠϕϯτΛ؅ཧ Value Object
  2. ςΩετ ͜Μͳײ͡ͷΠϯλʔϑΣʔεͰܨ͛Δ interface BookmarkFavoriteContact {
 
 interface View {
 


    fun showBookmarkList(bookmarkList: List<BookmarkEntity>)
 
 fun hideBookmarkList()
 
 fun showNetworkErrorMessage()
 
 fun showProgress()
 
 fun hideProgress()
 
 fun startAutoLoading()
 
 fun stopAutoLoading()
 
 fun showEmpty()
 
 fun hideEmpty()
 }
 
 interface Actions {
 
 fun onCreate(component: FragmentComponent,
 view: BookmarkFavoriteContact.View)
 
 fun onResume()
 
 fun onPause()
 
 fun onRefreshList()
 
 fun onScrollEnd(nextIndex: Int)
 
 fun onClickBookmark(bookmarkEntity: BookmarkEntity)
 }
 }
  3. ςΩετ MVPͳߏ੒ʹ͢Δ͜ͱͰϨΠϠʔͷ੹຿Λ໌֬ʹ͢Δ ▸ Activity / Fragment͸Model૚΁ͷΞΫηε͸ߦΘͣɺUIεϨουͰൃੜ ͢ΔΠϕϯτ͸Presenter΁ྲྀ͢ɻActivity / Fragment͸Viewͷૢ࡞ͷΈ ؔ৺Λ࣋ͭΑ͏ʹ͢Δɻ

    ▸ Presenter͸ड͚औͬͨΠϕϯτʹରԠ͢ΔModelͷૢ࡞Λߦ͏ʴૢ࡞ʹ Ԡͨ͡ViewͷίϯτϩʔϧΛߦ͏ɻViewͷ۩ମతͳૢ࡞ʹ͸ؔ৺Λ࣋ͨ ͣݺͼग़͚ͩ͢ɻ ▸ Model૚͸ن໛ʹΑΔ͚ͲDDDͬΆ͍Ξϓϩʔν͕ϝϯς͠΍͍͔͢ͳ ͱɻͨͩɺΞϓϦ͸API࿈ܞ͕΄΅ඞਢͳͷͰAPI͕བྷΉϞσϦϯά͸Ͳ ͏͢Ε͹͍͍Μ͡ΌΖͱ͍͏ײ͡ɻ
  4. ςΩετ ͜Μͳײ͡Ͱςετ࣌ʹDI͢ΔϞδϡʔϧΛࠩ͠ସ͑Δ͜ͱ͕Ͱ͖Δ͍ͧ @RunWith(AndroidJUnit4::class)
 class SplashActivityTest { @Rule
 @JvmField
 val activityRule:

    ActivityTestRule<SplashActivity> = object : ActivityTestRule<SplashActivity>(SplashActivity::class.java) {
 
 override fun beforeActivityLaunched() {
 super.beforeActivityLaunched()
 
 val app = InstrumentationRegistry.getTargetContext().applicationContext as App
 
 val appComponent = DaggerSplashActivityTest_TestApplicationComponent.builder()
 .applicationModule(ApplicationModule(app))
 .infraLayerModule(InfraLayerModule())
 .build()
 
 app.component = appComponent
 }
 } @Singleton
 @Component(modules = arrayOf(ApplicationModule::class, InfraLayerModule::class))
 interface TestApplicationComponent : ApplicationComponent {
 override fun activityComponent(): TestActivityComponent
 }
 
 @Subcomponent(modules = arrayOf(ActivityModule::class))
 interface TestActivityComponent : ActivityComponent {
 override fun fragmentComponent(): TestFragmentComponent
 }
 
 @Subcomponent(modules = arrayOf(TestInitializeFragmentModule::class))
 interface TestFragmentComponent : FragmentComponent {
 override fun inject(fragment: InitializeFragment)
 }
  5. ςΩετ @Module
 class TestInitializeFragmentModule() : FragmentModule() {
 
 override fun

    createInitializePresenter(context: Context): InitializeContact.Actions {
 return object : InitializeContact.Actions {
 
 override lateinit var view: InitializeContact.View
 
 override fun onCreate(component: FragmentComponent, view: InitializeContact.View) {
 this.view = view
 }
 
 override fun onResume() {
 
 }
 
 override fun onPause() {
 
 }
 
 override fun onClickButtonSetId(userId: String) {
 if (userId == "valid") {
 view.navigateToMain()
 } else if (userId == "invalid") {
 view.displayInvalidUserIdMessage()
 } else {
 view.showNetworkErrorMessage()
 }
 }
 }
 }
 } }
  6. ςΩετ ςετέʔε͸͜Μͳ;͍Μ͖ @Test
 fun ॳظදࣔͷ֬ೝ() {
 
 // ͸ͯͳIDೖྗཝ͕දࣔ.
 onView(withId(R.id.fragment_initialize_edit_hatena_id)).check(matches(isDisplayed()))


    
 // ͸ͯͳIDૹ৴Ϙλϯ͕ແޮͳঢ়ଶͰදࣔ.
 onView(withId(R.id.fragment_initialize_button_set_hatena_id)).check(matches(isDisplayed()))
 onView(withId(R.id.fragment_initialize_button_set_hatena_id)).check(matches(not(isEnabled())))
 
 // FAB͸දࣔ͞Εͯͳ͍.
 onView(withId(R.id.fab)).check(matches(not(isDisplayed())))
 } @Test
 fun ਖ਼͍͠͸ͯͳID͕ೖྗ͞ΕΔͱϝΠϯը໘ʹߦ͘() {
 onView(withId(R.id.fragment_initialize_edit_hatena_id)).perform(typeText("valid"))
 onView(withId(R.id.fragment_initialize_button_set_hatena_id))
 .perform(closeSoftKeyboard())
 .perform(click())
 
 // ϝΠϯը໘ͷπʔϧόʔ͕දࣔ͞ΕͨΒભҠͨ͠ͱΈͳ͢.
 onView(withId(R.id.app_bar_main_toolbar)).check(matches(isDisplayed()))
 }