Practical TDD Demonstrated

42
Agile Professionals Network Christchurch Alan Christensen Thanks to our sponsors… Practical TDD Demonstrated

description

Talk I gave at the Christchurch Agile Professionals Network (APN) on 29 August 2013. The code examples are linked to in the final slide.

Transcript of Practical TDD Demonstrated

Page 1: Practical TDD Demonstrated

Agile Professionals Network Christchurch

Alan Christensen

Thanks to our sponsors…

Practical TDD Demonstrated

Page 2: Practical TDD Demonstrated

Preamble

•Who am I?

•My TDD journey

Page 3: Practical TDD Demonstrated

Overview

•TDD to drive out design (live coding)

•Two approaches to TDD

•Bit on architecture and design (if time)

Page 4: Practical TDD Demonstrated

TDD for Design

•TDD is supposed to improve your design

•How does that work?

Page 5: Practical TDD Demonstrated

Test Driven Development

• It is a development technique (rather than a testing technique)

• Incremental (iterative) workflow

• Always write a failing test first (red)

• Only write the minimum code to pass the failing test (green)

• Improve code while all tests are passing (refactor)

http://www.agileapps.co.uk/methodology/continuous.html

Page 6: Practical TDD Demonstrated

Worked example

•Order confirmation (think shopping cart)

•Payment has already been taken

•What next?

Page 7: Practical TDD Demonstrated

Order Confirmation

•Flag order as Ready to Ship

•Notify customer, e.g. confirmation email

•Arrange shipment

Page 8: Practical TDD Demonstrated

coding time!

Page 9: Practical TDD Demonstrated

OrderConfirmationEmailBuilderOrderConfirmer

Test Test

OrderConfirmationEmailBuilder

Fake

Email TemplateEngine

Fake

MailSender

Fake

Page 10: Practical TDD Demonstrated

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

Page 11: Practical TDD Demonstrated

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

Page 12: Practical TDD Demonstrated

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)

Page 13: Practical TDD Demonstrated

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

•Use keyboard shortcuts

Page 14: Practical TDD Demonstrated

Disadvantages

•Any problems with this approach?

Page 15: Practical TDD Demonstrated

Two TDD approaches

•“Unit testing is out, vertical slice testing is in” - Sebastian Lambla (2013)

Page 16: Practical TDD Demonstrated

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

Page 17: Practical TDD Demonstrated

OrderConfirmationEmailBuilderOrderConfirmer

Test Test

OrderConfirmationEmailBuilder

Fake

Email TemplateEngine

Fake

MailSender

Fake

Page 18: Practical TDD Demonstrated

What is “unit” in “unit test”?

•All about isolation, but from what?

•Other classes or methods?

•Other systems (e.g. file system, email, database)?

•Other tests?

Page 19: Practical TDD Demonstrated

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

Page 20: Practical TDD Demonstrated

OrderConfirmationEmailBuilderOrderConfirmer

Test Test

OrderConfirmationEmailBuilder

Fake

Email TemplateEngine

Fake

MailSender

Fake

Page 21: Practical TDD Demonstrated

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

Page 22: Practical TDD Demonstrated

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

Page 23: Practical TDD Demonstrated

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)

Page 24: Practical TDD Demonstrated

MailSenderOrderConfirmer

Test

Page 25: Practical TDD Demonstrated

MailSenderOrderConfirmation

EmailBuilderOrderConfirmer

Test

Email TemplatingEngine

Page 26: Practical TDD Demonstrated

Code example

Page 27: Practical TDD Demonstrated

Refactor

•We decide to change how we notify customers (e.g. push notifications)

•We decide to re-shuffle some code...

•How will our two types of test fare?

Page 28: Practical TDD Demonstrated

OrderConfirmationEmailBuilderOrderConfirmer

Test Test

OrderConfirmationEmailBuilder

Fake

Email TemplateEngine

Fake

MailSender

Fake

Page 29: Practical TDD Demonstrated

OrderConfirmationCustomerNotifierOrderConfirmer

TestTest

OrderConfirmationCustomerNotifier

Fake

Email TemplateEngine

Fake

MailSender

Fake

Page 30: Practical TDD Demonstrated

MailSenderOrderConfirmation

EmailBuilderOrderConfirmer

Test

Email TemplatingEngine

Page 31: Practical TDD Demonstrated

MailSenderOrderConfirmationCustomerNotifierOrderConfirmer

Test

Email TemplatingEngine

Page 32: Practical TDD Demonstrated

vertical slices: the good

•More expressive tests

•More able to change implementation without breaking tests

Page 33: Practical TDD Demonstrated

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

Page 34: Practical TDD Demonstrated

http://www.woodwrightschool.com/ship-in-a-bottle-w-jim/http://www.woodwrightschool.com/ship-in-a-bottle-w-jim/

Page 35: Practical TDD Demonstrated

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

Page 36: Practical TDD Demonstrated
Page 37: Practical TDD Demonstrated

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

Page 38: Practical TDD Demonstrated

Traditional architecture

UI

Services

DB

Page 39: Practical TDD Demonstrated

Hexagonal Architecture

http://matteo.vaccari.name/blog/archives/154

Page 40: Practical TDD Demonstrated

Hexagonal Architecture - Alastair Cockburn

Page 41: Practical TDD Demonstrated

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-testing-is-in/

• http://martinfowler.com/articles/mocksArentStubs.html

• http://alistair.cockburn.us/Hexagonal+architecture

Page 42: Practical TDD Demonstrated

Questions?

Alan Christensen @christensena