Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.

TDD on android. Why and How? (Coding Serbia 2019)

31 visualizaciones

Publicado el

We all heard about TDD: test-driven development. The one side says: It produces better code and fewer bugs, other's see a waste of time. How much time does TDD cost? Does it even work on Android? Is it possible to develop an android app fully test driven? Should we do it? And if: should we only test Java classes? Should we use or avoid Robolectric? How do I even start?

Publicado en: Software
  • Sé el primero en comentar

  • Sé el primero en recomendar esto

TDD on android. Why and How? (Coding Serbia 2019)

  1. 1. TDD on Android Danny Preussler, CodingSerbia 2019
  2. 2. @PreusslerBerlin about:me • Started talking about testing in 2008
  3. 3. @PreusslerBerlin about:me • Switched to Java in 2003 • Switched to Kotlin in 2016 • Worked for eBay, Groupon, Viacom
  4. 4. @PreusslerBerlin sporttotal.tv • We are streaming under- medialised sports • Amateur and semi professional football • Professional Volleyball…
  5. 5. @PreusslerBerlin Let’s talk about tests
  6. 6. @PreusslerBerlin
  7. 7. @PreusslerBerlin “Code without tests is bad code.” “any code without test is a legacy code.” (Michael C. Feathers)
  8. 8. @PreusslerBerlin “Code without tests is bad code.” “any code without test is legacy code.” (Michael C. Feathers)
  9. 9. @PreusslerBerlin Tests give confidence “how do you know something works when you don’t have test for it?” (Robert ‘Uncle Bob’ Martin)
  10. 10. @PreusslerBerlin Tests allow refactoring “Refactoring without good test coverage is changing shit” (Martin Fowler)
  11. 11. @PreusslerBerlin TDD
  12. 12. @PreusslerBerlin History • Started with test first from XP in 1999 by Kent Beck • Just a rediscovery: test first was normal in early days of programming • Famous as TDD since Kent Becks book in 2003
  13. 13. @PreusslerBerlin History • Started with test first from XP in 1999 by Kent Beck • Just a rediscovery: test first was normal in early days of programming • Famous as TDD since Kent Becks book in 2003
  14. 14. @PreusslerBerlin History • Started with test first from XP in 1999 by Kent Beck • Just a rediscovery: test first was normal in early days of programming • Famous as TDD since Kent Becks book in 2003
  15. 15. @PreusslerBerlin How does it work?
  16. 16. @PreusslerBerlin The 3 rules of TDD • You must write a failing test before you write any production code. • You must not write more of a test than is sufficient to fail, or fail to compile. • You must not write more production code than is sufficient to make the currently failing test pass. nano-cycle (seconds)
  17. 17. @PreusslerBerlin The 3 rules of TDD • You must write a failing test before you write any production code. • You must not write more of a test than is sufficient to fail, or fail to compile. • You must not write more production code than is sufficient to make the currently failing test pass. nano-cycle (seconds)
  18. 18. @PreusslerBerlin The 3 rules of TDD • You must write a failing test before you write any production code. • You must not write more of a test than is sufficient to fail, or fail to compile. • You must not write more production code than is sufficient to make the currently failing test pass. nano-cycle (seconds)
  19. 19. @PreusslerBerlin The 3 rules of TDD • You must write a failing test before you write any production code. • You must not write more of a test than is sufficient to fail, or fail to compile. • You must not write more production code than is sufficient to make the currently failing test pass. nano-cycle (seconds)
  20. 20. @PreusslerBerlin Red Green Refactor • Create a unit tests that fails • Write just enough production code to makes that test pass. • Clean up the mess you just made. micro-cycle (minutes)
  21. 21. @PreusslerBerlin Red Green Refactor • Create a unit tests that fails • Write just enough production code to makes that test pass. • Clean up the mess you just made. micro-cycle (minutes)
  22. 22. @PreusslerBerlin Red Green Refactor • Create a unit tests that fails • Write just enough production code to makes that test pass. • Clean up the mess you just made. micro-cycle (minutes)
  23. 23. @PreusslerBerlin Red Green Refactor • Create a unit tests that fails • Write just enough production code to makes that test pass. • Clean up the mess you just made. micro-cycle (minutes)
  24. 24. @PreusslerBerlin Red Green Refactor • Make it fail • Make it work • Make it right micro-cycle (minutes)
  25. 25. @PreusslerBerlin WTF https://www.flickr.com/photos/jantruter/12794187835
  26. 26. @PreusslerBerlin Baby steps Based: our limited minds are not capable of two simultaneous goals: 1. Correct behavior. 2. Correct structure. https://www.flickr.com/photos/21561428@N03/4616816371
  27. 27. @PreusslerBerlin Red Green Refactor • You need red: • as no one tests the tests • In green: • Speed trumps design! • Make it dirty!
  28. 28. @PreusslerBerlin Red Green Refactor • Always be one step away from green bar
  29. 29. @PreusslerBerlin Red Green Refactor • Always be one step away from green bar • Think of new test-> write it down
  30. 30. @PreusslerBerlin Red Green Refactor • Always be one step away from green bar • Think of new test-> write it down • It’s getting ugly? -> write it down
  31. 31. @PreusslerBerlin Start somewhere
  32. 32. @PreusslerBerlin Write the tests that forces you to write the code you want to write
  33. 33. @PreusslerBerlin Start somewhere
  34. 34. @PreusslerBerlin Start somewhere
  35. 35. @PreusslerBerlin Start somewhere
  36. 36. @PreusslerBerlin Start somewhere
  37. 37. @PreusslerBerlin Start somewhere
  38. 38. @PreusslerBerlin Start somewhere
  39. 39. @PreusslerBerlin Start somewhere
  40. 40. @PreusslerBerlin Start somewhere
  41. 41. @PreusslerBerlin Start somewhere
  42. 42. @PreusslerBerlin Start somewhere
  43. 43. @PreusslerBerlin Write the tests that forces you to write the code you want to write Tip: Create a list of tests on paper
  44. 44. @PreusslerBerlin Isn’t that slow? https://pixabay.com/en/snail-illustration-drawing-yellow-1757756/
  45. 45. @PreusslerBerlin Isn’t it slow? Writing tests is slower than not writing tests. You’ll write at least as much test code as production code
  46. 46. @PreusslerBerlin Isn’t it slow? Writing tests is slower than not writing tests. You’ll write at least as much test code as production code
  47. 47. @PreusslerBerlin Isn’t it slow? Research shows that TDD: adds 10%—30% on initial costs = longer to complete their projects
  48. 48. @PreusslerBerlin Isn’t it slow? Research shows that TDD: • Reduces defect density by 60-90 % • Reduces production bug density by 40–80%
  49. 49. @PreusslerBerlin Isn’t it slow? Without TDD, you spend a few weeks writing code which mostly works and spend the next year "testing" and fixing many (but not all) of the bugs
  50. 50. @PreusslerBerlin Isn’t it slow? With TDD, you spend a year writing code which actually works. Then you do final integration testing for a few weeks.
  51. 51. @PreusslerBerlin Isn’t it slow? • Single feature will take longer • Bugfixing phase is shorter • Debugging disappears • Ci finds bugs before tester does • Long term it’s much faster no more big rewrite
  52. 52. @PreusslerBerlin Isn’t it slow? • Single feature will take longer • Bugfixing phase is shorter • Debugging disappears • Ci finds bugs before tester does • Long term it’s much faster no more big rewrite
  53. 53. @PreusslerBerlin Isn’t it slow? • Single feature will take longer • Bugfixing phase is shorter • Debugging disappears • Ci finds bugs before tester does • Long term it’s much faster no more big rewrite
  54. 54. @PreusslerBerlin Isn’t it slow? • Single feature will take longer • Bugfixing phase is shorter • Debugging disappears • Ci finds bugs before tester does • Long term it’s much faster no more big rewrite
  55. 55. @PreusslerBerlin Isn’t it slow? • Single feature will take longer • Bugfixing phase is shorter • Debugging disappears • Ci finds bugs before tester does • Long term it’s much faster no more big rewrite
  56. 56. @PreusslerBerlin Benefits •YAGNI and KISS out of the box •No more over-engineering •Test all business needs •Minimize debugging •Minimize use of Android devices
  57. 57. @PreusslerBerlin Benefits •YAGNI and KISS out of the box •No more over-engineering •Test all business needs •Minimize debugging •Minimize use of Android devices
  58. 58. @PreusslerBerlin Benefits •YAGNI and KISS out of the box •No more over-engineering •Test all business needs •Minimize debugging •Minimize use of Android devices
  59. 59. @PreusslerBerlin Benefits •YAGNI and KISS out of the box •No more over-engineering •Test all business needs •Minimize debugging •Minimize use of Android devices
  60. 60. @PreusslerBerlin Benefits •YAGNI and KISS out of the box •No more over-engineering •Test all business needs •Minimize debugging •Minimize use of Android devices
  61. 61. @PreusslerBerlin Benefits •It’s Gamification -> fun •Small Changes -> Small PRs •Always know what’s next
  62. 62. @PreusslerBerlin Benefits •It’s Gamification -> fun •Small Changes -> Small PRs •Always know what’s next
  63. 63. @PreusslerBerlin Benefits •It’s Gamification -> fun •Small Changes -> Small PRs •Always know what’s next
  64. 64. @PreusslerBerlin Benefits •Less stressful •Go home any time •Interrupt any time •No need for “flow”
  65. 65. @PreusslerBerlin Benefits •Less stressful •Go home any time •Interrupt any time •No need for “flow”
  66. 66. @PreusslerBerlin Benefits •Less stressful •Go home any time •Interrupt any time •No need for “flow”
  67. 67. @PreusslerBerlin Benefits •Less stressful •Go home any time •Interrupt any time •No need for “flow”
  68. 68. @PreusslerBerlin Android specifics
  69. 69. @PreusslerBerlin val tested = spy(PrivacyPolicyActivity()) @Nested inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(tested) .setContentView(R.layout.main) }
  70. 70. @PreusslerBerlin val tested = spy(PrivacyPolicyActivity()) @Nested inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(tested) .setContentView(R.layout.main) } }
  71. 71. @PreusslerBerlin val tested = spy(PrivacyPolicyActivity()) @Nested inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(tested) .setContentView(R.layout.main) } }
  72. 72. @PreusslerBerlin val tested = spy(PrivacyPolicyActivity()) @Nested inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(tested) .setContentView(R.layout.main) } }
  73. 73. @PreusslerBerlin val tested = spy(PrivacyPolicyActivity()) @Nested inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(tested) .setContentView(R.layout.main) } } protected
  74. 74. @PreusslerBerlin package android.app fun Activity.onCreate(bundle: Bundle?) = this.onCreate(bundle) github.com/ dpreussler/android-tdd-utils
  75. 75. @PreusslerBerlin val tested = spy(PrivacyPolicyActivity()) @Nested inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(tested) .setContentView(R.layout.main) } } Does this work?
  76. 76. @PreusslerBerlin Android SDK under test • Android classes can be loaded on JVM: build/generated/mockable-android-XX.jar • Removes finals and ALL the code!
  77. 77. @PreusslerBerlin Android SDK under test • Empty methods with default return values android { … testOptions { unitTests.returnDefaultValues = true } -> no code will run
  78. 78. @PreusslerBerlin The problem of v4… Activity • mockable.jar not existing for libraries, including support library L -> real code will run
  79. 79. @PreusslerBerlin The problem of v4… Activity • Helper method fun <T : FragmentActivity> T.prepareForTest(): T { … whenever(supportFragmentManager).thenReturn(mockSupportFragmentManager) whenever(fragmentManager).thenReturn(mockFragmentManager) whenever(layoutInflater).thenReturn(mockLayoutInflater) }
  80. 80. @PreusslerBerlin val tested = PrivacyPolicyActivity().prepareForTest() @Nested inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(tested) .setContentView(R.layout.main) } }
  81. 81. @PreusslerBerlin val tested = PrivacyPolicyActivity().prepareForTest() @Nested inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(tested) .setContentView(R.layout.main) } }
  82. 82. @PreusslerBerlin @Nested inner class `When started` { @Test fun `forwards lifecylce to viewmodel`() { tested.onStart() verify(viewModel).onStart() } } java.lang.NullPointerException at android.support.v17.leanback.app.PlaybackSupportFragment.setupChild FragmentLayout(PlaybackSupportFragment.java:730) at android.support.v17.leanback.app.PlaybackSupportFragment.onStart(Pl aybackSupportFragment.java:899)
  83. 83. @PreusslerBerlin fun Fragment.safeStart() { try { onStart() }catch (e: NullPointerException) {} catch (e: IllegalStateException) {} } github.com/ dpreussler/android-tdd-utils
  84. 84. @PreusslerBerlin Avoid Activity/Fragment code
  85. 85. @PreusslerBerlin Avoid activity and fragment code • Use life cycle aware components! override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) observeLifecycleIn(viewModel) } @OnLifecycleEvent(ON_START) fun onStart() { …. }
  86. 86. @PreusslerBerlin Avoid activity and fragment code • Testing android view classes are hard • Avoid needing to test them! • ViewModel encapsulates view state testable • Use the power of data binding
  87. 87. @PreusslerBerlin Avoid activity and fragment code • Testing android view classes are hard • Avoid needing to test them! • ViewModel encapsulates view state testable • Use the power of data binding
  88. 88. @PreusslerBerlin Avoid activity and fragment code • Testing android view classes are hard • Avoid needing to test them! • ViewModel encapsulates view state testable • Use the power of data binding
  89. 89. @PreusslerBerlin Avoid activity and fragment code • Testing android view classes are hard • Avoid needing to test them! • ViewModel encapsulates view state testable • Use the power of data binding
  90. 90. @PreusslerBerlin Data binding… XML ViewModelbind
  91. 91. @PreusslerBerlin Data binding… who is the view? • Solves the one big android question once and for all XML
  92. 92. @PreusslerBerlin What’s left? • Activities needs to be declared in manifest • Permissions for older devices
  93. 93. @PreusslerBerlin What’s left?
  94. 94. @PreusslerBerlin What’s left? • Manifest via lint lintOptions { check 'Registered' warningsAsErrors true }
  95. 95. @PreusslerBerlin What’s left? • Zero tolerance policy very valuable
  96. 96. @PreusslerBerlin What’s left? • Get access to merged manifest and resources: testOptions { unitTests.includeAndroidResources = true } com/android/tools/ test_config.properties
  97. 97. @PreusslerBerlin Whats left? • UI: text size, button text…
  98. 98. @PreusslerBerlin What about Espresso?
  99. 99. @PreusslerBerlin What about Espresso • need to be fast! fast feedback! • need to run continuously! Espresso can’t give any of those
  100. 100. @PreusslerBerlin What about Espresso • Test first? Yes! • TDD? No!
  101. 101. @PreusslerBerlin What about Robolectric?
  102. 102. @PreusslerBerlin Tired of issues like java.lang.NullPointerException at org.robolectric.manifest.MetaData .init(MetaData.java:55) at org.robolectric.manifest.AndroidM anifest.initMetaData(AndroidManif est.java:377).... ? Sleepy by Tomas; flickr.com/photos/tma/2438467223; CC 2.0 Don’t spent more time fixing your test setup than fixing your app Sleepy by Tomas; flickr.com/photos/tma/2438467223; CC 2.0 Still valid?
  103. 103. @PreusslerBerlin Robolectric 4
  104. 104. @PreusslerBerlin Robolectric 4
  105. 105. @PreusslerBerlin Robolectric 4
  106. 106. @PreusslerBerlin Robolectric 4 • Robolectric is just another “android device” when using Espresso like API • Not compatible with Junit5 • More stable now as of new API?! • Still slower
  107. 107. @PreusslerBerlin Robolectric 4 • Increases first test run by 6-8 sec • With ActivityTestRule: 12-14 sec
  108. 108. @PreusslerBerlin SPEED! • Build speed is important • Test new features in separate module! • Tip: Keep Robolectric tests in separate test folder: test, androidTest, sharedTest
  109. 109. @PreusslerBerlin Limitations • Custom view and animation code might get too hard
  110. 110. @PreusslerBerlin What about mocking ?
  111. 111. @PreusslerBerlin What about mocking • Mocks make our tests flaky • Only mock your outside dependency (think of modules not classes)
  112. 112. @PreusslerBerlin What about mocking • Mocks make our tests flaky • Only mock your outside dependency (think of modules not classes)
  113. 113. @PreusslerBerlin What about mocking • TDD changes the way your tests will be: Test1 Test2 Class1 Class2 Class3 Test3
  114. 114. @PreusslerBerlin What about mocking • TDD changes the way your tests will be: Test1 Class1 Class2 Class3
  115. 115. @PreusslerBerlin What about mocking • TDD changes the way your tests will be: Test1 Class1
  116. 116. @PreusslerBerlin What about mocking • TDD changes the way your tests will be: Test1 Class1 Class2 Class3
  117. 117. @PreusslerBerlin What about mocking • Tests will become more solid Test1 ViewModel Repository API
  118. 118. @PreusslerBerlin What about mocking • Tests will become more solid Test1 ViewModel Repository API Store Reducer SideEffects
  119. 119. @PreusslerBerlin What about mocking • Tests will become more solid Test1 ViewModel Repository API Store Reducer SideEffects
  120. 120. @PreusslerBerlin What about mocking • Mock your outside dependency (modules) Test1 ViewModel Repository API Store Reducer SideEffects
  121. 121. @PreusslerBerlin That’s not a UNIT test!? Test1 Class1 Class2 Class3
  122. 122. @PreusslerBerlin TDD and tests • Kent Beck spoke about behavior of the system in his TDD book • A “unit” does not mean every class/method! Unit came from Blackbox! • TDD tests behaviors not implementation details! • What your software does, is stable! How it does this, is unstable! TDD what went wrong: https://www.youtube.com/watch?v=EZ05e7EMOLM
  123. 123. @PreusslerBerlin TDD and tests • Kent Beck spoke about behavior of the system in his TDD book • A “unit” does not mean every class/method! Unit came from Blackbox! • TDD tests behaviors not implementation details! • What your software does, is stable! How it does this, is unstable! TDD what went wrong: https://www.youtube.com/watch?v=EZ05e7EMOLM
  124. 124. @PreusslerBerlin TDD and tests • Kent Beck spoke about behavior of the system in his TDD book • A “unit” does not mean every class/method! Unit came from Blackbox! • TDD tests behaviors not implementation details! • What your software does, is stable! How it does this, is unstable! TDD what went wrong: https://www.youtube.com/watch?v=EZ05e7EMOLM
  125. 125. @PreusslerBerlin TDD and tests • Kent Beck spoke about behavior of the system in his TDD book • A “unit” does not mean every class/method! Unit came from Blackbox! • TDD tests behaviors not implementation details! • What your software does, is stable! How it does this, is unstable! TDD what went wrong: https://www.youtube.com/watch?v=EZ05e7EMOLM
  126. 126. @PreusslerBerlin code coverage ?
  127. 127. @PreusslerBerlin What about code coverage In TDD 100% coverage is a side effect not a goal!
  128. 128. @PreusslerBerlin Wrap up
  129. 129. @PreusslerBerlin "Test only if you would want it to work.” Kent Beck
  130. 130. @PreusslerBerlin If it's worth building, it's worth testing If it's not worth testing, why are you wasting your time working on it?
  131. 131. @PreusslerBerlin If it's worth building, it's worth testing If it's not worth testing, why are you wasting your time working on it?
  132. 132. @PreusslerBerlin TDD on Android? • Its possible! • Might feel extreme • But it’s fun! https://www.flickr.com/photos/chefranden/14838138493
  133. 133. More resources • TDD what went wrong: https://www.youtube.com/watch?v=EZ05e7EMOLM • The three laws of TDD by Uncle Bob https://www.youtube.com/watch?v=AoIfc5NwRks • TDD for those who don't need it https://www.youtube.com/watch?v=a6oP24CSdUg • Test Driven Development by Example (Kent Beck)
  134. 134. More resources • https://online-training.jbrains.ca/p/wbitdd-01 • https://medium.com/androiddevelopers/write- once-run-everywhere-tests-on-android- 88adb2ba20c5 • github.com/sporttotal-tv/android-tdd- workshop • github.com/dpreussler/android-tdd-utils
  135. 135. TDD on Android @PreusslerBerlin
  136. 136. @PreusslerBerlin What about architecture ?
  137. 137. @PreusslerBerlin What about architecture? • TDD does not replace Architecture and Design • Have a vision in your head • NO big up front design • Defer architecture decisions as long as possible
  138. 138. @PreusslerBerlin What about architecture? • TDD does not replace Architecture and Design • Have a vision in your head • NO big up front design • Defer architecture decisions as long as possible
  139. 139. @PreusslerBerlin What about architecture? • TDD does not replace Architecture and Design • Have a vision in your head • No big up front design • Defer architecture decisions as long as possible
  140. 140. @PreusslerBerlin What about architecture? • TDD does not replace Architecture and Design • Have a vision in your head • No big up front design • Defer architecture decisions as long as possible
  141. 141. @PreusslerBerlin What about protoypes ?
  142. 142. @PreusslerBerlin What about Prototypes? hacking is fine but afterwards start from scratch!
  143. 143. @PreusslerBerlin What about MVP ?
  144. 144. @PreusslerBerlin What about MVP? MVP is a minimum feature set but no excuse for bad quality

×