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

TDD on Android

TDD on Android

Test driven development: Whats the reason? Whats the impact? What are the issues on Android?

Danny Preussler

June 25, 2018
Tweet

More Decks by Danny Preussler

Other Decks in Programming

Transcript

  1. @PreusslerBerlin History • Started with test first from XP in

    1999 by Kent Beck • Famous as TDD since Kent Becks book in 2003 • Just a rediscovery: test first was normal in early days of programming
  2. @PreusslerBerlin History • Started with test first from XP in

    1999 by Kent Beck • Famous as TDD since Kent Becks book in 2003 • Just a rediscovery: test first was normal in early days of programming
  3. @PreusslerBerlin History • Started with test first from XP in

    1999 by Kent Beck • Famous as TDD since Kent Becks book in 2003 • Just a rediscovery: test first was normal in early days of programming
  4. @PreusslerBerlin “Code without tests is bad code.” “any code without

    test is a legacy code.” (Michael C. Feathers)
  5. @PreusslerBerlin Tests give confidence “how do you know something works

    when you don’t have test for it?” (Robert ‘Uncle Bob’ Martin)
  6. @PreusslerBerlin Tests are documentation • The only doc that lives

    (with your code) • Test code will become more important than your production code
  7. @PreusslerBerlin “If you’re doing test-driven development well, you’ll never write

    comments in your code because your tests are a form of documentation for how your program should work,” (Alex Clark, Codecademy)
  8. @PreusslerBerlin What I learned • ”test after” does not work

    (enough) Test1 Test2 Class1 Class2 Class3 Test3
  9. @PreusslerBerlin …there is one other [discipline] that is, and that’s

    Accounting. The right mistake … that one-digit error can crash the company and send the offenders off to jail. How do accountants deal with that sensitivity? Well, they have disciplines.
  10. @PreusslerBerlin …there is one other [discipline] that is, and that’s

    Accounting. The right mistake … that one-digit error can crash the company and send the offenders off to jail. How do accountants deal with that sensitivity? Well, they have disciplines.
  11. @PreusslerBerlin …there is one other [discipline] that is, and that’s

    Accounting. The right mistake … that one-digit error can crash the company and send the offenders off to jail. How do accountants deal with that sensitivity? Well, they have disciplines.
  12. @PreusslerBerlin Dual entry book keeping Everything is said twice. Every

    transaction is entered two times — once on the credit side and once on the debit side. Those two transactions follow separate mathematical pathways until they end up at this wonderful subtraction on the balance sheet that has to yield to zero.
  13. @PreusslerBerlin Dual entry book keeping Everything is said twice. Every

    transaction is entered two times — once on the credit side and once on the debit side. Those two transactions follow separate mathematical pathways until they end up at this wonderful subtraction on the balance sheet that has to yield to zero.
  14. @PreusslerBerlin Dual entry book keeping Everything is said twice. Every

    transaction is entered two times — once on the credit side and once on the debit side. Those two transactions follow separate mathematical pathways until they end up at this wonderful subtraction on the balance sheet that has to yield to zero.
  15. @PreusslerBerlin Dual entry book keeping This is what test-driven development

    is: dual-entry bookkeeping. Everything is said twice — once on the test side and once on the production code side and everything runs in an execution that yields either a green bar or a red bar just like the zero on the balance sheet.
  16. @PreusslerBerlin Dual entry book keeping This is what test-driven development

    is: dual-entry bookkeeping. Everything is said twice — once on the test side and once on the production code side and everything runs in an execution that yields either a green bar or a red bar just like the zero on the balance sheet.
  17. @PreusslerBerlin Dual entry book keeping This is what test-driven development

    is: dual-entry bookkeeping. Everything is said twice — once on the test side and once on the production code side and everything runs in an execution that yields either a green bar or a red bar just like the zero on the balance sheet.
  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. @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. @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)
  21. @PreusslerBerlin Red Green Refactor • Make it fail • Make

    it work • Make it right micro-cycle (minutes)
  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. @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. @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)
  25. @PreusslerBerlin Babysteps The philosophy is based on the idea that

    our limited minds are not capable of pursuing the two simultaneous goals of all software systems: 1. Correct behavior. 2. Correct structure.
  26. @PreusslerBerlin Red Green Refactor • Always be one step away

    from green bar • Think of new test-> write it down
  27. @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
  28. @PreusslerBerlin Code is your ToDo list class PanoramaTrackerTest { @Test

    fun `should track button click`() { fail ("Danny forgot me") } }
  29. @PreusslerBerlin Why? • YAGNI and KISS out of the box

    • Test all business needs • Eliminate debugging
  30. @PreusslerBerlin My experience • Less coupled to implementation • Less

    mocking • Forces small changes • Interruptions from colleagues always possible • No need for a ”flow” • Less stress
  31. @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
  32. @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
  33. @PreusslerBerlin Isn’t it slow? Research shows that TDD: adds 10%—30%

    on initial costs = longer to complete their projects
  34. @PreusslerBerlin Isn’t it slow? Research shows that TDD: • Reduces

    defect density by 60-90 % • Reduces production bug density by 40–80%
  35. @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 With TDD, you spend a year writing code which actually works. Then you do final integration testing for a few weeks.
  36. @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
  37. @PreusslerBerlin TDD and 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
  38. @PreusslerBerlin TDD and 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
  39. @PreusslerBerlin TDD and 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
  40. @PreusslerBerlin TDD and 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
  41. @PreusslerBerlin TDD and architecture Write the tests that forces you

    to write the code you want to write Tip: Create a list of tests on paper
  42. @PreusslerBerlin Android SDK under test • Android classes can be

    loaded on JVM: build/generated/mockable-android-XX.jar • No more finals!
  43. @PreusslerBerlin Android SDK under test • Empty methods with default

    return values android { … testOptions { unitTests.returnDefaultValues = true } -> no code will run
  44. @PreusslerBerlin The problem of v4… Activity • mockable.jar not existing

    for libraries, including support library L -> real code will run
  45. @PreusslerBerlin Solutions for v4… Activity • Robolectric • Helper method

    fun <T : FragmentActivity> T.prepareForTest(): T { … whenever(supportFragmentManager).thenReturn(mockSupportFragmentManager) whenever(fragmentManager).thenReturn(mockFragmentManager) whenever(layoutInflater).thenReturn(mockLayoutInflater) }
  46. @PreusslerBerlin val binding = mock<ActivityPrivacyPolicyBinding>() val tested = PrivacyPolicyActivity().prepareForTest( @Nested

    inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(binding).viewModel = navigationViewModel } }
  47. @PreusslerBerlin val binding = mock<ActivityPrivacyPolicyBinding>() val tested = PrivacyPolicyActivity().prepareForTest( @Nested

    inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(binding).viewModel = navigationViewModel } }
  48. @PreusslerBerlin val binding = mock<ActivityPrivacyPolicyBinding>() val tested = PrivacyPolicyActivity().prepareForTest( @Nested

    inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(binding).viewModel = navigationViewModel } } protected
  49. @PreusslerBerlin val binding = mock<ActivityPrivacyPolicyBinding>() val tested = PrivacyPolicyActivity().prepareForTest( @Nested

    inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(binding).viewModel = navigationViewModel } } protected
  50. @PreusslerBerlin val binding = mock<ActivityPrivacyPolicyBinding>() val tested = PrivacyPolicyActivity().prepareForTest( @Nested

    inner class `When created` { @Test fun `sets viewmodel`() { tested.onCreate(null) verify(binding).viewModel = navigationViewModel } } protected
  51. @PreusslerBerlin The power of data binding • Testing android view

    classes are hard • So let’s make sure we don’t need to test them!
  52. @PreusslerBerlin Data binding… who is the view? • Solves the

    one big android question once and for all
  53. @PreusslerBerlin What’s left? • Activities needs to be declared in

    manifest • Permissions for older devices (internet)
  54. @PreusslerBerlin What’s left? • Manifest via lint lintOptions { check

    'Registered' warningsAsErrors true } * Has issues with Gradle Plugin 3.0 and Kotlin
  55. @PreusslerBerlin What about Espresso • problem: • need to be

    fast! • need to run continuously • fast feedback
  56. @PreusslerBerlin Tired of issues like java.lang.NullPointerException at org.robolectric.manifest.MetaData. init(MetaData.java:55) at

    org.robolectric.manifest.AndroidMa nifest.initMetaData(AndroidManifes t.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?
  57. @PreusslerBerlin Prototypes, POC and MVPs • For prototypes: hacking together

    is fine But after: start from scratch and build it test driven • For MVP: an MVP is a minimum feature set but no excuse for bad quality
  58. @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?
  59. @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?
  60. @PreusslerBerlin TDD on Android? • its possible! • its fun!

    https://www.flickr.com/photos/chefranden/14838138493
  61. @PreusslerBerlin Tools used • Some test utils code for FragmentActivity,

    check TestUtils.kt github.com/ sporttotal-tv/android-tdd-workshop
  62. @PreusslerBerlin More resources • Test Driven Development by Example (Kent

    Beck) • https://cleancoders.com/videos • https://online-training.jbrains.ca/p/wbitdd-01 • http://news.codecademy.com/test-driven- development/