Slide 1

Slide 1 text

Testdrive your android app Danny Preussler Head of Mobile

Slide 2

Slide 2 text

@PreusslerBerlin The source • Please download github.com/ sporttotal-tv/android-tdd-workshop • Branch master • Run FirstTest.test() @PreusslerBerlin

Slide 3

Slide 3 text

@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

Slide 4

Slide 4 text

@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

Slide 5

Slide 5 text

@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

Slide 6

Slide 6 text

@PreusslerBerlin Let’s talk about tests

Slide 7

Slide 7 text

@PreusslerBerlin “Code without tests is bad code.” “any code without test is a legacy code.” (Michael C. Feathers)

Slide 8

Slide 8 text

@PreusslerBerlin “Code without tests is bad code.” “any code without test is legacy code.” (Michael C. Feathers)

Slide 9

Slide 9 text

@PreusslerBerlin Tests give confidence “how do you know something work when you don’t have test for it?” (Robert ‘Uncle Bob’ Martin)

Slide 10

Slide 10 text

@PreusslerBerlin Tests allow refactoring “Refactoring without good test coverage is changing shit” (Martin Fowler)

Slide 11

Slide 11 text

@PreusslerBerlin Tests are documentation • The only doc that lives (with your code) • Test code will become more important than your production code

Slide 12

Slide 12 text

@PreusslerBerlin About me • Talking about testing for 10y now • Its all about discipline • I am a learner like you • Let’s dive in together

Slide 13

Slide 13 text

@PreusslerBerlin What I learned • ”test after” does not work (enough) Class1 Class2 Class3

Slide 14

Slide 14 text

@PreusslerBerlin What I learned • ”test after” does not work (enough) Test1 Test2 Class1 Class2 Class3 Test3

Slide 15

Slide 15 text

@PreusslerBerlin What I learned • ”test after” does not work (enough) Test1 Class1 Class2 Class3

Slide 16

Slide 16 text

@PreusslerBerlin Look outside the box

Slide 17

Slide 17 text

@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.

Slide 18

Slide 18 text

@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.

Slide 19

Slide 19 text

@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.

Slide 20

Slide 20 text

@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.

Slide 21

Slide 21 text

@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.

Slide 22

Slide 22 text

@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.

Slide 23

Slide 23 text

@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.

Slide 24

Slide 24 text

@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.

Slide 25

Slide 25 text

@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.

Slide 26

Slide 26 text

@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)

Slide 27

Slide 27 text

@PreusslerBerlin How does it work?

Slide 28

Slide 28 text

@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)

Slide 29

Slide 29 text

@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)

Slide 30

Slide 30 text

@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)

Slide 31

Slide 31 text

@PreusslerBerlin Red Green Refactor • Make it fail • Make it work • Make it right micro-cycle (minutes)

Slide 32

Slide 32 text

@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)

Slide 33

Slide 33 text

@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)

Slide 34

Slide 34 text

@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)

Slide 35

Slide 35 text

@PreusslerBerlin WTF

Slide 36

Slide 36 text

@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.

Slide 37

Slide 37 text

@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

Slide 38

Slide 38 text

@PreusslerBerlin Why? • YAGNI and KISS out of the box • eliminate debugging

Slide 39

Slide 39 text

@PreusslerBerlin Why? • Test all business needs • Less coupled to implementation • Less mocking • Forces small changes • TDD is more about design

Slide 40

Slide 40 text

@PreusslerBerlin Isn’t that slow? https://pixabay.com/en/snail-illustration-drawing-yellow-1757756/

Slide 41

Slide 41 text

@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 TDD adds 10% — 30% on initial costs = longer to complete their projects

Slide 42

Slide 42 text

@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 TDD adds 10% — 30% on initial costs = longer to complete their projects

Slide 43

Slide 43 text

@PreusslerBerlin Isn’t it slow? Research shows that TDD: • Reduces defect density by 60-90 % • Reduces production bug density by 40–80%

Slide 44

Slide 44 text

@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.

Slide 45

Slide 45 text

@PreusslerBerlin Isn’t it slow? • Feature takes longer • You write at least as much test code as production code

Slide 46

Slide 46 text

@PreusslerBerlin Isn’t it slow? • Bugfixing phase is shorter • Debugging disappears • Ci finds bugs before tester does • Long term it’s much faster no more big rewrite

Slide 47

Slide 47 text

@PreusslerBerlin Let’s code! • Goal: countdown app @PreusslerBerlin

Slide 48

Slide 48 text

@PreusslerBerlin Live coding • The countdown @PreusslerBerlin

Slide 49

Slide 49 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_001 @PreusslerBerlin

Slide 50

Slide 50 text

@PreusslerBerlin Let’s talk Android

Slide 51

Slide 51 text

violating the most basics principles of Software Engineering! flickr.com/photos/cobblucas/4831501753, Stop by Lucas Cobb, CC by 2.0

Slide 52

Slide 52 text

@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

Slide 53

Slide 53 text

@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

Slide 54

Slide 54 text

@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

Slide 55

Slide 55 text

@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

Slide 56

Slide 56 text

@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

Slide 57

Slide 57 text

@PreusslerBerlin Separation of concerns (1974)

Slide 58

Slide 58 text

@PreusslerBerlin D.R.Y.

Slide 59

Slide 59 text

@PreusslerBerlin Violations of DRY are typically referred to as WET solutions, which is commonly taken to stand for either "write everything twice" or "we enjoy typing” (http://en.wikipedia.org/wiki/Don't_repeat_yourself)

Slide 60

Slide 60 text

@PreusslerBerlin

Slide 61

Slide 61 text

@PreusslerBerlin Clean Code

Slide 62

Slide 62 text

@PreusslerBerlin S.O.L.I.D.

Slide 63

Slide 63 text

@PreusslerBerlin View architecture

Slide 64

Slide 64 text

@PreusslerBerlin MVP View Presenter Model

Slide 65

Slide 65 text

@PreusslerBerlin MVVM View ViewModel Model

Slide 66

Slide 66 text

@PreusslerBerlin Live coding • viewmodel @PreusslerBerlin

Slide 67

Slide 67 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_002 @PreusslerBerlin

Slide 68

Slide 68 text

@PreusslerBerlin Lets talk about Activities • now the tricky part starts https://www.flickr.com/photos/muchadoaboutnothing/438734626

Slide 69

Slide 69 text

@PreusslerBerlin Android SDK under test • Android classes can be loaded on JVM: build/generated/mockable-android-XX.jar • No more finals!

Slide 70

Slide 70 text

@PreusslerBerlin Android SDK under test • Empty methods with default return values android { … testOptions { unitTests.returnDefaultValues = true } -> no code will run

Slide 71

Slide 71 text

@PreusslerBerlin Live coding • Classic Activity @PreusslerBerlin

Slide 72

Slide 72 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_003a @PreusslerBerlin

Slide 73

Slide 73 text

@PreusslerBerlin Dependency Injection

Slide 74

Slide 74 text

@PreusslerBerlin Dependency Inversion Inversion of Control Dependency Injection ? ? ?

Slide 75

Slide 75 text

@PreusslerBerlin The Dependency Inversion Principle High level entities should not depend on low level details.

Slide 76

Slide 76 text

@PreusslerBerlin Inversion of Control Who initiates a message Hollywood's Law: don't call me, I'll call you.

Slide 77

Slide 77 text

@PreusslerBerlin Inversion of Control Stop using new

Slide 78

Slide 78 text

@PreusslerBerlin Inversion of Control Common implementations: ● Factory ● Service Locator ● Dependency Injection

Slide 79

Slide 79 text

@PreusslerBerlin Inversion of Control Common implementations: ● Factory tracker = Factory.createTracker() ● Service Locator ● Dependency Injection

Slide 80

Slide 80 text

@PreusslerBerlin Inversion of Control Common implementations: ● Factory ● Service Locator tracker = Locator.get(Tracker.class) ● Dependency Injection

Slide 81

Slide 81 text

@PreusslerBerlin Inversion of Control Common implementations: ● Factory ● Service Locator ● Dependency Injection @Inject Tracker tracker;

Slide 82

Slide 82 text

@PreusslerBerlin Live coding • Activity with injection @PreusslerBerlin

Slide 83

Slide 83 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_003b @PreusslerBerlin

Slide 84

Slide 84 text

@PreusslerBerlin Rotation

Slide 85

Slide 85 text

@PreusslerBerlin Rotation • Many different solutions • Let’s go with view model from Architecture Components

Slide 86

Slide 86 text

@PreusslerBerlin Rotation • Many different solutions • Let’s go with view model from Architecture Components

Slide 87

Slide 87 text

@PreusslerBerlin life cycle: rotation onCreate onStart onResume onPause onStop onDestroy onCreate onStart onResume ViewModel

Slide 88

Slide 88 text

@PreusslerBerlin Problem • Needs a FragmentActivity public static ViewModelProvider of(FragmentActivity activity) { L

Slide 89

Slide 89 text

@PreusslerBerlin The problem of v4… Activity • mockable.jar not existing for libraries, including support library L -> real code will run

Slide 90

Slide 90 text

@PreusslerBerlin Live coding • FragmentActivity @PreusslerBerlin

Slide 91

Slide 91 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_004a @PreusslerBerlin

Slide 92

Slide 92 text

@PreusslerBerlin Live coding • ViewModel @PreusslerBerlin

Slide 93

Slide 93 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_004b @PreusslerBerlin

Slide 94

Slide 94 text

@PreusslerBerlin What’s left? • Activities needs to be declared in manifest • Permissions for older devices (internet)

Slide 95

Slide 95 text

@PreusslerBerlin Live coding • Manifest via lint lintOptions { check 'Registered' warningsAsErrors true } * Has issues with Gradle Plugin 3.0 and Kotlin @PreusslerBerlin

Slide 96

Slide 96 text

@PreusslerBerlin Live coding • Manifest via lint

Slide 97

Slide 97 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_005 @PreusslerBerlin

Slide 98

Slide 98 text

@PreusslerBerlin Live coding • Zero tolerance policy very valuable

Slide 99

Slide 99 text

@PreusslerBerlin What’s left? • Permissions for older devices (internet)

Slide 100

Slide 100 text

@PreusslerBerlin An alternative

Slide 101

Slide 101 text

@PreusslerBerlin Lets talk about data binding • Testing android view classes are hard • So let’s make sure we don’t need to test them!

Slide 102

Slide 102 text

@PreusslerBerlin Data binding full picture XML ViewModel bind

Slide 103

Slide 103 text

@PreusslerBerlin Data binding… who is the view? • Solves the one big android question once and for all

Slide 104

Slide 104 text

@PreusslerBerlin ViewModel in Data Binding

Slide 105

Slide 105 text

@PreusslerBerlin ViewModel in data binding

Slide 106

Slide 106 text

@PreusslerBerlin Live coding • Data binding @PreusslerBerlin

Slide 107

Slide 107 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_006 @PreusslerBerlin

Slide 108

Slide 108 text

@PreusslerBerlin How do I…

Slide 109

Slide 109 text

@PreusslerBerlin .. show a toast class SeriesViewModel : Viewmodel() { … @Bindable var error = ObservableField()

Slide 110

Slide 110 text

@PreusslerBerlin .. show a toast viewModel.error.addOnPropertyChangedCallback( object : OnPropertyChangedCallback() { override fun onPropertyChanged(…) { showToast(viewModel.error.get() } })

Slide 111

Slide 111 text

@PreusslerBerlin .. show a toast (alternative) @BindingAdapter("showError") fun ViewGroup.onErrorAppeared(error: String?){ errorString?.let { showToast(context, error)) } }

Slide 112

Slide 112 text

@PreusslerBerlin Data binding full picture XML Activity ViewModel (un)bind bind Life cycle aware class (un)bind

Slide 113

Slide 113 text

@PreusslerBerlin Whats left? • UI: text size, button text…

Slide 114

Slide 114 text

@PreusslerBerlin What about Espresso • problem: • need to be fast! • need to run continuously • fast feedback

Slide 115

Slide 115 text

@PreusslerBerlin Live coding • Espresso @PreusslerBerlin

Slide 116

Slide 116 text

@PreusslerBerlin Live coding • Result branch tdd_checkpoint_007 @PreusslerBerlin

Slide 117

Slide 117 text

@PreusslerBerlin What about Robolectric?

Slide 118

Slide 118 text

@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

Slide 119

Slide 119 text

@PreusslerBerlin What’s wrong with Robolectric? • Developers used too much magic forgot what unit test should be • Your tests rely on correct 3rd party implementation • Tests itself becomes flaky • It’s slower than pure JUnit

Slide 120

Slide 120 text

@PreusslerBerlin Android today • Projects not designed to be testable have often need for Robolectric

Slide 121

Slide 121 text

@PreusslerBerlin Time to wrap up

Slide 122

Slide 122 text

@PreusslerBerlin Limitations • Custom view and animation code might get too hard

Slide 123

Slide 123 text

@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

Slide 124

Slide 124 text

@PreusslerBerlin "Test only if you would want it to work.” Kent Beck

Slide 125

Slide 125 text

@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?

Slide 126

Slide 126 text

@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?

Slide 127

Slide 127 text

@PreusslerBerlin Remember! • Never write new functionality without test first • Tests need to be refactored and clean!

Slide 128

Slide 128 text

@PreusslerBerlin TDD on Android? • its possible! • its fun! https://www.flickr.com/photos/chefranden/14838138493

Slide 129

Slide 129 text

@PreusslerBerlin TDD on Android? Unit tests (even with TDD) are NOT the only tests you need

Slide 130

Slide 130 text

@PreusslerBerlin Tools used • github.com/MarkusAmshove/Kluent • github.com/nhaarman/mockito-kotlin • Final mocking with mockito2: github.com/mockito/mockito/wiki/What%2 7s-new-in-Mockito-2#mock-the- unmockable-opt-in-mocking-of-final- classesmethods

Slide 131

Slide 131 text

@PreusslerBerlin Tools used • Protected onCreate call in Kotlin: github.com/ dpreussler/android-tdd-utils • Test friendly dependency Injection: github.com/ stephanenicolas/toothpick

Slide 132

Slide 132 text

@PreusslerBerlin Tools used • Some test utils code for FragmentActivity, check TestUtils.kt github.com/ sporttotal-tv/android-tdd-workshop

Slide 133

Slide 133 text

@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/

Slide 134

Slide 134 text

Testdrive your android app @PreusslerBerlin