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

Testing Android apps with Kotlin

Testing Android apps with Kotlin

This talk covers what to test, how to test, what good unit tests are and how you can achieve nice tests using KotlinTest (and mockk). It covers unit tests mostly since I consider them to be much more important and more neglected than integration and UI tests. Koin was left out since Arnaud Guiliani gave a dedicated Koin talk at the same meetup.

D0ed2f28dd13ddfb192ebe198623924c?s=128

Wolfram Rittmeyer

July 30, 2019
Tweet

Transcript

  1. None
  2. Why tests? @RittmeyerW

  3. Why automated tests? @RittmeyerW

  4. Why tests? • Less manual testing • Safety net when

    refactoring and maintaining • Helps flesh out structure • Helps create a clean API • Can be the spec of the code @RittmeyerW
  5. Why tests? • Less manual testing • Safety net when

    refactoring • Helps flesh out structure • Helps create a clean API • Can be the spec of the code @RittmeyerW
  6. To me, legacy code is simply code without tests. @RittmeyerW

    Michael C. Feathers, Working Effectively With Legacy Code
  7. Which tests? @RittmeyerW

  8. Which tests? @RittmeyerW https://martinfowler.com/bliki/TestPyramid.html

  9. Which tests? @RittmeyerW https://watirmelon.blog/testing-pyramids/

  10. None
  11. Good unit tests, part I • Automated and repeatable •

    Easy to implement • Runs quickly • Consistent in results • Fully isolated @RittmeyerW
  12. Good unit tests, part II • Can I run all

    the unit tests I’ve written in no more than a few minutes? • Can I run all the unit tests I’ve written at the push of a button? • Can I write a basic test in no more than a few minutes @RittmeyerW Roy Osherove: The Art of Unit Testing
  13. Why KotlinTest? @RittmeyerW

  14. Why KotlinTest? • Two reasons: – It‘s help you write

    nicely structured tests – It‘s helps you write clean assertions @RittmeyerW
  15. Specification in Detail @RittmeyerW

  16. Specification in detail • Multiple styles – StringSpec – ShouldSpec

    – BDD-Spec – Feature-Spec – And more... @RittmeyerW
  17. None
  18. None
  19. None
  20. None
  21. None
  22. Assertions @RittmeyerW

  23. Matchers • Two styles – Infix • someString should startWith(„prefix“)

    – Extension functions • someString.shouldStartWith(„prefix“) • Negation • someString shouldNot startWith(„prefix“) @RittmeyerW
  24. None
  25. Matchers - General @RittmeyerW shouldBe() shouldBeTypeOf() shouldBeInstanceOf() shouldBeNull() shouldBeSameInstanceAs() shouldBeOneOf()

    shouldHaveSameHashCodeAs()
  26. Matchers – and more • Collections • Strings • Integers

    / floating point numbers • URIs • Date values • and more @RittmeyerW
  27. Matchers – Collection Inspectors forAll() forNone() forOne() forAtMostOne() forAtMost(n) ...

    @RittmeyerW
  28. None
  29. None
  30. None
  31. Test one thing only! • Helps to name the test

    properly • Helps to find the root cause of failures faster • Indicator of testing multiple things: – Too many asserts per test @RittmeyerW
  32. You should run additional concern checks in separate, self-contained unit

    tests so that you can see what really fails. @RittmeyerW Roy Osherove, The Art of Unit Testing
  33. Multivalue tests @RittmeyerW

  34. Property based testing • Populates properties with random values •

    Uses reasonable edge cases • You can create custom generators @RittmeyerW
  35. None
  36. Table-driven testing • You have parameters and expected results •

    Useful for on device calculations @RittmeyerW
  37. None
  38. Problems @RittmeyerW

  39. Problems • No instrumentation tests with KotlinTest • Not always

    properly displayed in IDE • IDE support is missing – Especially jump to source • Plugin available, but still buggy @RittmeyerW
  40. What else? @RittmeyerW

  41. What else? • mockk – Mocking lib • Koin –

    Dependency injection @RittmeyerW
  42. mockk • Mocking library with Kotlin in mind • Easier

    to use than Mockito @RittmeyerW
  43. None
  44. None
  45. UI Tests @RittmeyerW

  46. UI Tests • Robot pattern or • Kakao with screens

    / page objects @RittmeyerW
  47. UI Tests • Robot pattern or • Kakao with screens

    / page objects • But @RittmeyerW
  48. UI Tests • Not needed for all kind of integration

    tests • Some can be done with unit tests • For example Retrofit integration • But separate those since they last longer! @RittmeyerW
  49. Robot pattern • Made popular by Jake Wharton • Variation

    of page object pattern • Uses DSLish constructs @RittmeyerW
  50. None
  51. None
  52. None
  53. None
  54. My TDD(ish) workflow @RittmeyerW

  55. My TDD(ish) workflow • Let‘s consider starting with a login

    screen @RittmeyerW
  56. Starting with the presenter • I happen to start with

    the presenter • Needed – Presenter / ViewModel (Object under test) – View – Navigator – Interactor for non-view related app logic @RittmeyerW
  57. Starting with the presenter • Assertion done via – View

    – Navigator • Normally not via interactor @RittmeyerW
  58. Interactor • Assertions might be done differently to those of

    the presenter • Either result (sealed objects) or • Interaction with mocked objects is tested @RittmeyerW
  59. General guideline • Try to test interactions as little as

    possible • Try to concentrate on results instead • Alas, it‘s not always possible @RittmeyerW
  60. And what about the view? • Initially plenty of TODO(whatever)

    calls • Implementing them is usually trivial • Sometimes requires adjustments to presenter @RittmeyerW
  61. And what about the view? • Not part of unit

    test • Espresso tests with robot pattern – To test navigation – Interaction on one screen • e.g. visibility modifications – Based on mocks @RittmeyerW
  62. And what about the view? • Used sparingly • Consider

    splitting up in two sets: – One for dev testing • Failures do trigger notifications of team – One for pre-prod testing that is kind of supervised automatic testing • Failures do not trigger notifications of team @RittmeyerW
  63. Why only TDDish? @RittmeyerW

  64. Why only TDDish? • It does not help flesh out

    architecture @RittmeyerW
  65. None
  66. None
  67. None
  68. There are two ways to make changes to a system:

    1. Edit and Pray 2. Cover and Modify @RittmeyerW https://barryosull.com/blog/notes-from-working-effectively-with-legacy-code/
  69. None