TDD in Practice
Alan Christensen
@christensena
Preamble
• Who am I?
• MyTDD journey
Overview
• TDD to drive out design (live coding)
• Two approaches toTDD
• Bit on architecture and design
TDD for Design
• TDD is supposed to improve your design
• How does that work?
Worked example
• Order confirmation (think shopping cart)
• Payment has already been taken
• What next?
Order Confirmation
• Flag order as Ready to Ship
• Notify customer, e.g. confirmation email
• Arrange shipment
coding time!
OrderConfirmation
EmailBuilderOrderConfirmer
Test Test
OrderConfirmation
EmailBuilder
Fake
Email Template
Engine
Fake
Review
• Try to keep the Red Green Refactor
discipline
• NCrunch is wonderful but costs $$$
• Use test naming to document behaviour
• Asserts should match test naming (so
typically one assert per test)
• Arrange/Act/Assert helps with readability
Review: Mocking
• Prefer state based tests
• Prefer manual (static) fakes over dynamic
• Prefer stubs if using dynamic mocks
• Use adapters over untestable code
• Use adapters/facades to make application
code more expressive of intent
Review:TDD Design
• Starting with test helps focus on good API
• When test setups (Arrange) get large, it
usually tells us we need to factor code into
smaller pieces (classes, modules whatever)
• Tests help us focus on one small
component at a time
• Often end up with more general, re-usable
components (with rigorous tests)
Lots of tiny classes!
• Is this a bad thing?
• Best use a DI container
• used right they fade into the background
• Use IDE code navigation tools
• e.g. Go to Definition, Find Usages, Ctrl-T
in R#
• Use keyboard shortcuts
Disadvantages
• Any problems with this approach?
Two TDD approaches
• “Unit testing is out, vertical slice testing is
in” - Sebastian Lambla (2013)
Two TDD Approaches
“A lot of the bad advice about TDD has come
from believing that it means testing a module in
isolation from other modules, so that you
essentially can only have one class under test
and you have to have everything else mocked
out.” - Ian Cooper (NDC in Oslo 2013 TDD:
where did it all go wrong?)
OrderConfirmation
EmailBuilderOrderConfirmer
Test Test
OrderConfirmation
EmailBuilder
Fake
Mail Template
Engine
Fake
What is a unit test?
• All about isolation, but from what?
• Other classes or methods?
• Other systems (e.g. file system, email,
database)?
• Other tests?
Isolation approach
• Focused test suites, specify behaviour of
small units (e.g. classes)
• Substitute out all dependencies
• Tests inevitably specify implementation
details to some extent
OrderConfirmation
EmailBuilderOrderConfirmer
Test Test
OrderConfirmation
EmailBuilder
Fake
Mail Template
Engine
Fake
isolated: the good
• Focused tests allow us to focus on one
thing at a time
• When tests fail, the source of problem is
usually easy to identify
• Set ups are small, tests always fast
• Encourages well-factored code
• Tests relatively easy to write
isolated: the bad
• Tends to lock in to a specific
implementation
• Tests can become a liability, slowing down
refactoring
• Can lead to focus on implementation
details over business value
vertical slice approach
• Tests talk to public API only
• Tests verify expected results, but not how they
are arrived at
• Isolation is between tests, not between “units”.
• Test suite per feature instead of per class
• Still don’t touch external systems (i.e. still fast
and stable)
MailSenderOrderConfirmer
Test
MailSender
OrderConfirmation
EmailBuilder
OrderConfirmer
Test
Email Templating
Engine
vertical slices: the good
• More expressive tests
• More able to change implementation
without breaking tests
vertical slices: the bad
• Harder to drive out your design
• Easy to “get lost” in the implementation
without close guidance of your tests
• Harder to pinpoint bugs when tests fail
• Can be more difficult to write tests
http://www.woodwrightschool.com/ship-in-a-bottle-w-jim/
So which to use?
• The answer of course: it depends...
• Isolation when “discovering” your design
• Replace them as appropriate with vertical
slice tests
• Delete brittle tests! Use code coverage
tools to ensure you still have coverage
Other tips
• Use “builder” pattern for making test data
• Refactor test code like “real” code. Keep it
clean!
• There is no “right” way to do things
Traditional architecture
UI
Services
DB
Hexagonal Architecture
http://matteo.vaccari.name/blog/archives/154
Hexagonal Architecture - Alastair Cockburn
Links
• Source code and link to these slides including this one!
https://github.com/christensena/TDDIntro
• TDD, where did it all go wrong? (Ian Cooper, NDC 2013)
http://vimeo.com/68375232
• http://codebetter.com/sebastienlambla/2013/07/11/unit-testing-is-out-vertical-slice-testin
• http://martinfowler.com/articles/mocksArentStubs.html
• http://alistair.cockburn.us/Hexagonal+architecture
Questions?
Reruns
• Repeating this talk 29 August at
Christchurch APN
Alan Christensen
@christensena

TDD In Practice