unit testing, tdd and the walking skeleton
DESCRIPTION
Slides from my DDD Scotland 2011 session.TRANSCRIPT
IBM Software Group
© 2009 IBM Corporation
Unit Testing, Test Driven Development and the Walking Skeleton
Seb Rose
Twitter: @sebrose
Blog: claysnow.blogspot.com
E-mail: [email protected]
Phone: 01721 788178
IBM Software Group | Rational software
Innovation for a smarter planet2
Agenda
Introduction
GOOS
Walking Skeleton
Test Driven Development
Unit Testing
Myths
Wrap up
IBM Software Group | Rational software
Innovation for a smarter planet3
Don’t we all know enough about testing?
Lots of software has insufficient automated testing How much manual testing goes on at YOUR workplace?
Testing is still seen as a 2nd class activity What do YOU drop when you’re under time pressure?
Tests are often written after the code Is YOUR code always testable?
Plenty see tests as a drag on development Do your tests inhibit changes to YOUR architecture?
Not everyone cares about all the tests Does everyone run YOUR tests every check-in?
Who cares when YOUR tests break?
IBM Software Group | Rational software
Innovation for a smarter planet4
Agenda
Introduction
GOOS
Walking Skeleton
Test Driven Development
Unit Testing
Myths
Wrap up
IBM Software Group | Rational software
Innovation for a smarter planet5
One book to rule them all?
Pulls together current thinking Walking skeleton
Acceptance Test Driven Development
Test Driven Development
Includes OO design philosophy Ports and connectors
Small decoupled classes
Do not Repeat Yourself
Tell, don’t ask
Worked example
IBM Software Group | Rational software
Innovation for a smarter planet6
DISCLAIMER
I am not affiliated to Freeman/Pryce
I have never worked with them
I barely know them
The book stands on its own
Mailing list: [email protected]
IBM Software Group | Rational software
Innovation for a smarter planet7
Agenda
Introduction
GOOS
Walking Skeleton
Test Driven Development
Unit Testing
Myths
Wrap up
IBM Software Group | Rational software
Innovation for a smarter planet8
What is a walking skeleton?
Automatically buildable
Automatically deployable
Automatically testable
No functionality required
Initial architecture
IBM Software Group | Rational software
Innovation for a smarter planet9
Why start with the skeleton?
The infrastructure of build, deploy, test can be time consuming to implement You WILL need it, so do it first
If you don’t do it now, WHEN will you have time?
The skeleton gives early visibility
Without a skeleton it is hard to drive development OUTSIDE-IN Acceptance Test Driven Development (ATDD) is a powerful tool
IBM Software Group | Rational software
Innovation for a smarter planet10
Acceptance Test Driven Development
Document functionality using acceptance tests
Tests readable by ‘business people’ FIT / Fitnesse
Cucumber
Can replace specifications / user stories in some environments.
Needs commitment from whole organisation
IBM Software Group | Rational software
Innovation for a smarter planet11
Red, Green, Refactor
IBM Software Group | Rational software
Innovation for a smarter planet12
Agenda
Introduction
GOOS
Walking Skeleton
Test Driven Development
Unit Testing
Myths
Wrap up
IBM Software Group | Rational software
Innovation for a smarter planet13
What is TDD?
Test Driven Development aka Test Driven Design
A software development practice Popularised by agile processes (like XP)
A development process that generates, among other things, (automated) unit tests
TDD is NOT a replacement for system/integration testing.
IBM Software Group | Rational software
Innovation for a smarter planet14
The basics
Write a failing test
Write just enough code to make it pass
Refactor
Repeat
IBM Software Group | Rational software
Innovation for a smarter planet15
IBM Software Group | Rational software
Innovation for a smarter planet16
When does unit testing become TDD?
The test is written BEFORE the code
The test is RUN before the code is written
The test must FAIL
The code is written to SATISFY the test
Code is ONLY written to satisfy a test
Run all tests
The tests must PASS
REFACTOR the code & tests to production quality
Ensure all tests still pass
Remember TDD code must be of PRODUCTION QUALITY
IBM Software Group | Rational software
Innovation for a smarter planet17
TDD and “agile”
Agile Manifesto: Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan
TDD is one of several agile practices “Agile practices are not optional” – Mike Kohn
IBM Software Group | Rational software
Innovation for a smarter planet18
Emergent design
Big Up Front Design impedes delivery of working code, but Initially it’s uncomfortable working without BUFD
Planning & partitioning work is harder
Architecture still important Walking skeleton – initial application architecture
Intentional – deliberate conscious decisions
Rework is inevitable TDD makes refactoring less error prone
BUT since tests are of ‘production’ quality this is cheap
IBM Software Group | Rational software
Innovation for a smarter planet19
Executable Documentation
Prefer documenting your design in tests Documentation can often be out of date
Comments can often be out of date
Tests run with every build, so CANNOT be broken
Not an excuse for NO documentation Architecture
Vision
Scenarios/Use cases/Competencies
More confidence in documentation that can be verified automatically i.e. tests
IBM Software Group | Rational software
Innovation for a smarter planet20
Challenges
At first I found that: Working without detailed designs was uncomfortable
Writing tests first was unnatural
Ensuring testability was confusing
Productivity decreased
Over time I noticed that: The tests gave me confidence
New habits became familiar
Defects and regressions decreased
IBM Software Group | Rational software
Innovation for a smarter planet21
For TDD to work
Tests need to be easy to run All developers and build processes need to run them
Tests need to be fast to run Ran every few minutes or seconds
Partition test suites to keep fast
Build needs to be quick Partition application to keep fast
Test failures need to be handled Process
Team commitment
IBM Software Group | Rational software
Innovation for a smarter planet22
Stop Press: “TDD no substitute for testing”
TDD relies on Unit Tests aka Developer Tests
Unit Tests: Document the code
Can’t become out of date
Well structured (like production code)
Don’t cover traditional “test team” scenarios
Testing is just as important as ever Integration, System, Acceptance etc.
IBM Software Group | Rational software
Innovation for a smarter planet23
TDD summary
TDD is a DEVELOPER activity
It delivers: (Automatically) Testable software
Higher test coverage
Lower defect rates
Reliable refactoring
TDD is not a replacement for integration or system testing
IBM Software Group | Rational software
Innovation for a smarter planet24
Agenda
Introduction
GOOS
Walking Skeleton
Test Driven Development
Unit Testing
Myths
Wrap up
IBM Software Group | Rational software
Innovation for a smarter planet25
What is Unit Testing?
A unit test
isolates a part of the program
tests a single behaviour
clearly identifies any reason for failure
documents expected behaviour
runs quickly
IBM Software Group | Rational software
Innovation for a smarter planet26
No free lunch
Writing unit tests takes time and skill
Refactoring unit tests takes time and skill
Running unit tests takes time
Interpreting unit test failures takes time and skill
Fixing defects takes time and skill
Fixing defects early costs less than fixing them late
“Unit Testing is the most cost effective testing activity you can do. Defects removed in Unit Testing cost around 10 times less than defects removed in Functional verification and around 40 times less than defects removed by Systems or Integration testing.”
IBM Software Group | Rational software
Innovation for a smarter planet27
Testability
Testability needs to be designed in TDD ensures code is testable
Code with hidden dependencies is hard to test Dependency Injection/Inversion
Pass dependencies into code under test
Write factories that permit injection of test doubles
Interfaces should be cohesive
Wide interfaces encourage unnecessary coupling
Avoid globals, singletons etc.
Retro-fitting unit tests is hard Take small steps
Introduce a ‘seam’ – c.f. Working Effectively with Legacy Code
IBM Software Group | Rational software
Innovation for a smarter planet28
A test is not a unit test if:
It talks to the database
It communicates across the network
It touches the file system
It can’t run at the same time as other unit tests
You have to do special things to your environment (such as editing config files) to run it
(Michael Feathers’ blog, 2005)
IBM Software Group | Rational software
Innovation for a smarter planet29
Necessity
Test observable behaviour Don’t modify encapsulation to aid testing
If a behaviour isn’t observable through the public interface what is it for?
Don’t slavishly write one test per method Test behaviours
Some methods may not need any dedicated tests
Methods that implement useful behaviours may need many tests
Choose test variants carefully Edge conditions
Invalid inputs
Multiple invocations
Assert invariants
Error signalling
IBM Software Group | Rational software
Innovation for a smarter planet30
Granularity
Test a SINGLE observable behaviour It is tempting to combine related behaviours in a single test – DON’T
… even if EXACTLY the same steps are needed
public void shouldSortTwoStringsAndReportCorrectSize() {
SortedSet<String> animals = new TreeSet<String>();
animals.add(“Zebra”);
animals.add(“Anteater”);
assertEquals(2, animals.size());
assertEquals(“Anteater”, animals.first());
assertEquals(“Zebra”, animals.last());
}
IBM Software Group | Rational software
Innovation for a smarter planet31
Understandability
Test a single observable behaviour (again)
Name tests to describe the behaviour under test Describe nature of the test
Is it checking that preconditions are enforced?
Is a dependency going to signal an error?
Long names are fine – you only type them once
Be precise
shouldReturnCorrectValue is not a good name for a test
shouldReturnCorrectSumOfTwoIntegersWithoutOverflow
should_return_correct_sum_of_two_integers_without_overflow
When a test fails you want to know WHAT WENT WRONG You don’t want to reverse engineer the test
You don’t want to run smaller tests to isolate the failure
IBM Software Group | Rational software
Innovation for a smarter planet32
Maintainability
Unit Tests should be written to same quality as Production code Tests will be maintained and read just as often as production code
Code is communication to other developers not just a compiler
Organise tests into cohesive suites
Refactor tests to avoid duplication Use suites to perform common set up/tear down operations
Extract common code into methods
Extract common functionality into classes
Remove redundant tests
IBM Software Group | Rational software
Innovation for a smarter planet33
Reiteration: 5 -ities
Testability
Necessity
Granularity
Understandability
Maintainability
MUNGT ?
TeNGUM?
IBM Software Group | Rational software
Innovation for a smarter planet34
Tests can only be run once they have been written
Resist pressure to add unit tests ‘later’ Untested code should not be committed to codebase
How can you know code is testable?
There are always more pressing things to do tomorrow
“Legacy code is code without unit tests” – Michael Feathers
Keep tests in same changeset as functionality they test Aids traceability and auditing
Subject tests to same quality control as production code Apply usual coding standards
Buddy check/peer review should examine completeness of tests
IBM Software Group | Rational software
Innovation for a smarter planet35
Tests are only useful when they are run
Run the tests automatically Developer builds should run them while writing code
Continuous Integration server builds should run them
Release/nightly builds should run them
Test failure == build failure At each stage of the process, fail the build if a test is broken
Failing tests should automatically fail the build
Automatic notification necessary
Respond quickly Fixing a failed test is highest priority
Responsibility of whole team
Resist pressure for “just for now” fix
IBM Software Group | Rational software
Innovation for a smarter planet36
Demonstrate value of unit tests
Unit testing takes time, up front Lots of evidence that it saves time later on
Still need to demonstrate that its working in your team
Collect metrics now (some suggestions) Coverage - how much code is tested?
Defects per feature
Regressions per iteration
Velocity
Collect metrics continuously Integrate collection with your process
Publish trends
Expect a learning curve
IBM Software Group | Rational software
Innovation for a smarter planet37
Agenda
Introduction
GOOS
Walking Skeleton
Test Driven Development
Unit Testing
Myths
Wrap up
IBM Software Group | Rational software
Innovation for a smarter planet38
A few myths I hope I’ve dispelled
“Testing is a job for testers”
“Now that we ‘do’ TDD we don’t need any testers”
“Tests are only important while the code is being written”
“Tests aren’t as important as production code”
“What does it matter what I call it? It’s only a test!”
“Why should I fix it? It’s not my code!”
“We can always add the tests next iteration”
“There’s not enough time to write tests”
IBM Software Group | Rational software
Innovation for a smarter planet39
Agenda
Introduction
GOOS
Walking Skeleton
Test Driven Development
Unit Testing
Myths
Wrap up
IBM Software Group | Rational software
Innovation for a smarter planet40
Questions?
Most of the information from this session can also be found in: “Testing Times”
published this month in C Vu, the magazine of ACCU
www.accu.org
Contact me: [email protected]
@sebrose
01721 788178
claysnow.blogspot.com
IBM Software Group | Rational software
Innovation for a smarter planet41
References Growing Object-Oriented Software Guided by Tests – Freeman/Pryce
Bridging the communications gap – Gojko Adzic
Fit for developing software – Mugridge/Cunningham
Test Driven Development - Kent Beck
Working Effectively with Legacy Code – Michael Feathers
Succeeding with Agile – Mike Cohn
Refactoring: Improving the Design of Existing Code – Martin Fowler
Clean code – Robert Martin
JUnit Recipes – J.B. Rainsberger
xUnit Test Patterns – Gerard Meszaros