@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 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
Let’s
talk about
tests
Slide 6
Slide 6 text
@PreusslerBerlin
“Code without tests is bad code.”
“any code without test is a legacy code.”
(Michael C. Feathers)
Slide 7
Slide 7 text
@PreusslerBerlin
“Code without tests is bad code.”
“any code without test is legacy code.”
(Michael C. Feathers)
Slide 8
Slide 8 text
@PreusslerBerlin
Tests give confidence
“how do you know something works when you
don’t have test for it?”
(Robert ‘Uncle Bob’ Martin)
Slide 9
Slide 9 text
@PreusslerBerlin
Tests allow refactoring
“Refactoring without good test coverage
is changing shit”
(Martin Fowler)
Slide 10
Slide 10 text
@PreusslerBerlin
Tests are documentation
• The only doc that lives (with your code)
• Test code will become more important than
your production code
Slide 11
Slide 11 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 12
Slide 12 text
@PreusslerBerlin
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
How does
it work?
Slide 27
Slide 27 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 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
Red Green Refactor
• Make it fail
• Make it work
• Make it right
micro-cycle (minutes)
Slide 31
Slide 31 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 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
WTF
Slide 35
Slide 35 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 36
Slide 36 text
@PreusslerBerlin
Red Green Refactor
• Always be one step away from green bar
Slide 37
Slide 37 text
@PreusslerBerlin
Red Green Refactor
• Always be one step away from green bar
• Think of new test-> write it down
Slide 38
Slide 38 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 39
Slide 39 text
@PreusslerBerlin
Code is your ToDo list
class PanoramaTrackerTest {
@Test
fun `should track button click`() {
fail ("Danny forgot me")
}
}
Slide 40
Slide 40 text
@PreusslerBerlin
Why?
• YAGNI and KISS out of the box
• Test all business needs
• Eliminate debugging
Slide 41
Slide 41 text
@PreusslerBerlin
My experience
• Less coupled to implementation
• Less mocking
• Forces small changes
• Interruptions from colleagues always possible
• No need for a ”flow”
• Less stress
Slide 42
Slide 42 text
@PreusslerBerlin
Start somewhere
Slide 43
Slide 43 text
@PreusslerBerlin
Start somewhere
Slide 44
Slide 44 text
@PreusslerBerlin
Start somewhere
Slide 45
Slide 45 text
@PreusslerBerlin
Start somewhere
Slide 46
Slide 46 text
@PreusslerBerlin
Start somewhere
Slide 47
Slide 47 text
@PreusslerBerlin
Start somewhere
Slide 48
Slide 48 text
@PreusslerBerlin
Start somewhere
Slide 49
Slide 49 text
@PreusslerBerlin
Start somewhere
Slide 50
Slide 50 text
@PreusslerBerlin
Start somewhere
Slide 51
Slide 51 text
@PreusslerBerlin
Start somewhere
Slide 52
Slide 52 text
@PreusslerBerlin
Start somewhere
Slide 53
Slide 53 text
@PreusslerBerlin
Isn’t that
slow?
https://pixabay.com/en/snail-illustration-drawing-yellow-1757756/
Slide 54
Slide 54 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
Slide 55
Slide 55 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
Slide 56
Slide 56 text
@PreusslerBerlin
Isn’t it slow?
Research shows that TDD:
adds 10%—30% on initial costs
= longer to complete their projects
Slide 57
Slide 57 text
@PreusslerBerlin
Isn’t it slow?
Research shows that TDD:
• Reduces defect density by 60-90 %
• Reduces production bug density by 40–80%
Slide 58
Slide 58 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 59
Slide 59 text
@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
Slide 60
Slide 60 text
@PreusslerBerlin
TDD and
architecture
Slide 61
Slide 61 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 62
Slide 62 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 63
Slide 63 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 64
Slide 64 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 65
Slide 65 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 66
Slide 66 text
@PreusslerBerlin
Android
Slide 67
Slide 67 text
@PreusslerBerlin
Android SDK under test
• Android classes can be loaded on JVM:
build/generated/mockable-android-XX.jar
• No more finals!
Slide 68
Slide 68 text
@PreusslerBerlin
Android SDK under test
• Empty methods with default return values
android {
…
testOptions {
unitTests.returnDefaultValues = true
}
-> no code will run
Slide 69
Slide 69 text
@PreusslerBerlin
The problem of v4… Activity
• mockable.jar not existing for libraries,
including support library L
-> real code will run
Slide 70
Slide 70 text
@PreusslerBerlin
Solutions for v4… Activity
• Robolectric
• Helper method
fun T.prepareForTest(): T {
…
whenever(supportFragmentManager).thenReturn(mockSupportFragmentManager)
whenever(fragmentManager).thenReturn(mockFragmentManager)
whenever(layoutInflater).thenReturn(mockLayoutInflater)
}
Slide 71
Slide 71 text
@PreusslerBerlin
val binding = mock()
val tested = PrivacyPolicyActivity().prepareForTest(
@Nested
inner class `When created` {
@Test
fun `sets viewmodel`() {
tested.onCreate(null)
verify(binding).viewModel =
navigationViewModel
}
}
Slide 72
Slide 72 text
@PreusslerBerlin
val binding = mock()
val tested = PrivacyPolicyActivity().prepareForTest(
@Nested
inner class `When created` {
@Test
fun `sets viewmodel`() {
tested.onCreate(null)
verify(binding).viewModel =
navigationViewModel
}
}
Slide 73
Slide 73 text
@PreusslerBerlin
val binding = mock()
val tested = PrivacyPolicyActivity().prepareForTest(
@Nested
inner class `When created` {
@Test
fun `sets viewmodel`() {
tested.onCreate(null)
verify(binding).viewModel =
navigationViewModel
}
}
protected
Slide 74
Slide 74 text
@PreusslerBerlin
val binding = mock()
val tested = PrivacyPolicyActivity().prepareForTest(
@Nested
inner class `When created` {
@Test
fun `sets viewmodel`() {
tested.onCreate(null)
verify(binding).viewModel =
navigationViewModel
}
}
protected
Slide 75
Slide 75 text
@PreusslerBerlin
val binding = mock()
val tested = PrivacyPolicyActivity().prepareForTest(
@Nested
inner class `When created` {
@Test
fun `sets viewmodel`() {
tested.onCreate(null)
verify(binding).viewModel =
navigationViewModel
}
}
protected
Slide 76
Slide 76 text
@PreusslerBerlin
package android.app
fun Activity.onCreate(bundle: Bundle?)
= this.onCreate(bundle)
github.com/
dpreussler/android-tdd-utils
Slide 77
Slide 77 text
@PreusslerBerlin
The power of data binding
• Testing android view classes are hard
• So let’s make sure we don’t need to test them!
Slide 78
Slide 78 text
@PreusslerBerlin
Data binding…
XML ViewModel
bind
Slide 79
Slide 79 text
@PreusslerBerlin
Data binding…
who is the view?
• Solves the one
big android question once
and for all
Slide 80
Slide 80 text
@PreusslerBerlin
What’s left?
• Activities needs to be declared in manifest
• Permissions for older devices (internet)
Slide 81
Slide 81 text
@PreusslerBerlin
What’s left?
• Manifest via lint
lintOptions {
check 'Registered'
warningsAsErrors true
}
* Has issues with Gradle Plugin 3.0 and Kotlin
Slide 82
Slide 82 text
@PreusslerBerlin
What’s left?
Slide 83
Slide 83 text
@PreusslerBerlin
What’s left?
• Zero tolerance policy very valuable
Slide 84
Slide 84 text
@PreusslerBerlin
What’s left?
• Permissions for older devices (internet)
Slide 85
Slide 85 text
@PreusslerBerlin
Whats left?
• UI: text size, button text…
Slide 86
Slide 86 text
@PreusslerBerlin
What about Espresso
• problem:
• need to be fast!
• need to run continuously
• fast feedback
Slide 87
Slide 87 text
@PreusslerBerlin
What about
Robolectric?
Slide 88
Slide 88 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
Still valid?
Slide 89
Slide 89 text
@PreusslerBerlin
Limitations
• Custom view and animation code might get too
hard
Slide 90
Slide 90 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 91
Slide 91 text
@PreusslerBerlin
"Test only if you would
want it to work.”
Kent Beck
Slide 92
Slide 92 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 93
Slide 93 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 94
Slide 94 text
@PreusslerBerlin
Remember!
• Never write new functionality without test first
• Tests need to be refactored and clean!
Slide 95
Slide 95 text
@PreusslerBerlin
TDD on Android?
• its possible!
• its fun!
https://www.flickr.com/photos/chefranden/14838138493
Slide 96
Slide 96 text
@PreusslerBerlin
TDD on Android?
Unit tests (even with TDD)
are NOT the only tests you need
Slide 97
Slide 97 text
@PreusslerBerlin
Tools used
• Protected onCreate call in Kotlin:
github.com/
dpreussler/android-tdd-utils
Slide 98
Slide 98 text
@PreusslerBerlin
Tools used
• Some test utils code for FragmentActivity,
check TestUtils.kt
github.com/
sporttotal-tv/android-tdd-workshop
Slide 99
Slide 99 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/