Pro Yearly is on sale from $80 to $50! »

Build Testble Apps for Androidの紹介 / introduce-build-testable-apps-for-android

Build Testble Apps for Androidの紹介 / introduce-build-testable-apps-for-android

DeNA.apk#1 【Google I/O 報告会】の発表資料です
https://dena.connpass.com/event/128184/

7867fe52a9be4257508a516d4df61578?s=128

tkmnzm

May 16, 2019
Tweet

Transcript

  1. Build Testable Apps for Androidͷ঺հ SWETάϧʔϓ Nozomi Takuma

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

  3. Session Summary AndroidΞϓϦʹ͓͚Δࣗಈςετͷ ઓུ TestableͳΞϓϦͷߏ੒ Unit/Integra=on/E2Eςετͷ࣮૷

  4. ࣗಈςετͷઓུ Scope/Speed/Fidelityͷόϥϯε ςετϐϥϛου

  5. ࣗಈςετͷઓུ

  6. TODOΞϓϦΛྫʹ Cri=cal User Journey λεΫΛ࡞੒͢Δ λεΫͷਐḿΛ֬ೝ͢Δ

  7. Monolithic Architecture

  8. Ϋϥε͝ͱΛ੾Γ཭͢ͷ ͕೉͍͠ είʔϓͷখ͍͞ςετ ͕Ͱ͖ͣɺE2Eςετ͕
 ૿͍͑ͯ͘ Monolithic Architecture

  9. Layered Architecture

  10. Unitςετ͸໰୊ͳ͠ ࠷ऴతʹ֤Layer͕Monoli=cʹͳΓ
 ΠϯςάϨʔγϣϯςετΑΓ΋
 E2Eςετ͕૿͍͑ͯ͘ Layered Architecture

  11. Modular Architecture

  12. Architecture Component Naviga=on Data Binding Live Data Room View ViewModel

    Model
  13. શମਤ

  14. TDD(TDD&ATDDͬΆ͍?)

  15. TDD(TDD&ATDDͬΆ͍?) ͱ͍͏લஔ͖͕͋Γ
 E2Eςετͷઆ໌͔Β͸͡·Γ·͢

  16. E2E Test

  17. Happy PathΛ
 ςετ E2E Test Scope

  18. E2E Test Code @Test fun createTask() { // start up

    Tasks screen val ac=vityScenario = Ac=vityScenario.launch(TasksAc=vity::class.java) dataBindingIdlingResource.monitorAc=vity(ac=vityScenario) // Click on the "+" bu\on, add details, and save onView(withId(R.id.fab_add_task)).perform(click()) onView(withId(R.id.add_task_=tle)).perform(typeText("=tle")) onView(withId(R.id.add_task_descrip=on)).perform(typeText("descrip=on")) onView(withId(R.id.fab_save_task)).perform(click()) // Then verify task is displayed on screen onView(withText("=tle")).check(matches(isDisplayed())) }
  19. E2E Test Code @Test fun createTask() { // start up

    Tasks screen val ac=vityScenario = Ac=vityScenario.launch(TasksAc=vity::class.java) dataBindingIdlingResource.monitorAc=vity(ac=vityScenario) // Click on the "+" bu\on, add details, and save onView(withId(R.id.fab_add_task)).perform(click()) onView(withId(R.id.add_task_=tle)).perform(typeText("=tle")) onView(withId(R.id.add_task_descrip=on)).perform(typeText("descrip=on")) onView(withId(R.id.fab_save_task)).perform(click()) // Then verify task is displayed on screen onView(withText("=tle")).check(matches(isDisplayed())) } Ac=vityΛىಈ͠
 ෳ਺ͷFragmentʹ·͕ͨͬͯ ϑϩʔΛݕূ
  20. Integra=on Test

  21. Integra=on Test Scope ςετͷείʔϓΛ খ͘͢͞Δ

  22. Test Double ্ʹ͍͘΄Ͳ࣮ࡍͷ
 ৼΔ෣͍ʹۙ͘ͳΔ Fidelity

  23. AddEditTaskFragmentTest VerifyͰ͖ΔΑ͏
 ϞοΫʹஔ͖׵͑ ࠓճ͸಺෦ʹMapΛ࣋ͭ Fakeʹஔ͖׵͑


  24. Integra=on Test Code @Test fun validTask_isSaved() { // GIVEN -

    On the "Add Task" screen. val navController = mock(NavController::class.java) val bundle = AddEditTaskFragmentArgs(null, getApplica=onContext<Context>().getString(R.string.add_task)).toBundle() val scenario = launchFragmentInContainer<AddEditTaskFragment>(bundle, R.style.AppTheme) scenario.onFragment { Naviga=on.setViewNavController(it.view!!, navController) }
 .. } FragmentΛىಈ͠
 ϞοΫͷNavControllerΛ
 ౉͢
  25. Integra=on Test Code @Test fun validTask_isSaved() {
 .. // WHEN

    - Valid =tle and descrip=on combina=on and click save onView(withId(R.id.add_task_=tle)).perform(replaceText("=tle")) onView(withId(R.id.add_task_descrip=on)).perform(replaceText("descrip=on")) onView(withId(R.id.fab_save_task)).perform(click()) .. }
  26. Integra=on Test Code @Test fun validTask_isSaved() { .. // THEN

    - Verify that the repository saved the task val tasks = (repository.getTasksBlocking(true) as Result.Success).data assertEquals(tasks.size, 1) assertEquals(tasks[0].=tle, "=tle") verify(navController).navigate( AddEditTaskFragmentDirec=ons .ac=onAddEditTaskFragmentToTasksFragment(ADD_EDIT_RESULT_OK)) } Fake͔ΒσʔλΛ औಘͯ͠ݕূ

  27. Integra=on Test Code @Test fun validTask_isSaved() { .. // THEN

    - Verify that the repository saved the task val tasks = (repository.getTasksBlocking(true) as Result.Success).data assertEquals(tasks.size, 1) assertEquals(tasks[0].=tle, "=tle") verify(navController).navigate( AddEditTaskFragmentDirec=ons .ac=onAddEditTaskFragmentToTasksFragment(ADD_EDIT_RESULT_OK)) } ਖ਼͍͠ύϥϝʔλͰNaviga=on Ͱ͖͍ͯΔ͔ݕূ
  28. Unit Test

  29. Unit Test Summary TaskLocalDataStoreTest ৄࡉͳ࣮૷ΑΓͲ͏ৼΔ෣͏͔ DaoΛMockͰ͸ͳ͘Fakeʹͯ͠
 ςετ Corou=neͷςετ༻ͷrunBlockingTest

  30. Tes=ng Codelab ηογϣϯͷ಺༰Λ࣮ࡍʹखΛಈ͔ ͠ͳ͕ΒֶͿ͜ͱ͕Ͱ͖Δ g.co/codelabs/android-tes=ng

  31. AndroidX Test Local TestͱInstrumenta=on Testͷࠩ෼Λٵऩ͢Δ
 unified API ҆ఆੑ΍૬ޓӡ༻ੑͷڧԽ Local JVM

    supportͷڧԽ Architecture component support
  32. Nitrogen Unified APIͰॻ͔ΕͨςετΛ
 ༷ʑͳ؀ڥͰγʔϜϨεʹ
 ࣮ߦͰ͖ΔPlanorm

  33. Nitrogen͕ϦϦʔε͞ΕΔ·Ͱ android { sourceSets { String sharedTestDir = 'src/sharedTest/java' test

    { java.srcDir sharedTestDir } androidTest { java.srcDir sharedTestDir } }
  34. CodelabͰͷ࢖͍෼͚ androidTest E2E sharedTest Integra=on Test(FragmentɾRoom·ΘΓ) test Unit Test

  35. Nitrogen EAP 2019 2Qʹalpha൛ϦϦʔε༧ఆͳͷͰ ͦΖͦΖ৮ΕΔΑ͏ʹͳΔͱظ଴ bit.ly/nitrogen-eap

  36. ·ͱΊ ࣗಈςετͷઓུͱͦΕΛ࣮ݱ͢ΔArchitectuteͷ঺հ CodelabΛ௨ͯ͡खΛಈ͔͠ͳ͕ΒֶͿ͜ͱ͕Ͱ͖Δ Unified APIΛ࢖༻ͨ͠γʔϜϨεͳ࣮ߦ(Nitrogen EAP!)

  37. Session Info h\ps://events.google.com/io/schedule/events/ 7bd73b37-1bca-40b3-b8e9-6efe3a9ac234 h\ps://www.youtube.com/watch?v=VJi2vmaQe6w