THE “NO TIME FOR TESTING” DEATH SPIRAL
The best is the confidence that we can change the code w/o
Fear kills progress.
VISIBLE UNCERTAINTY IN TEST-FIRST AND TEST-LATER
Test-driven development (TDD) is a test-first
software development process that relies on the
repetition of a very short development cycle and
encourages simple designs and inspires
It doesn’t matter how much you read about it, it’s
like riding bike: you need to try it to learn it and
DRY (don’t repeat yourself). Every piece of knowledge must have a
single, unambiguous, authoritative representation within a system.
SOLID (Single responsibility, Open/closed, Liskov substitution, Interface
segregation, Dependency inversion). Strictly following TDD and the SOLID principles
will bring code clean, testable and flexible, so that it can be easily
refactored, leveraging on the unit tests as scaffolding to prevent regression.
KISS (keep it simple stupid). Simplicity should be a key goal in design and
unnecessary complexity should be avoided.
YAGNI (you aren’t gonna need it). Always implement things when you actually need
them, never when you just foresee that you need them. Paradox: by not considering
the future of your code, you make your code much more likely to be adaptable in the
Fake it till you make it. Imitate confidence so that as the confidence produces
success, it will generate real confidence. Avoid getting stuck in a self-fulfilling
prophecy related to one's fear of not being confident.
RGR (red/green/refactor) development cycle
Break bigger tests into smaller steps.
Make baby steps (confident to implement that will teach you something).
Learn and improve from real feedback (clean-up redundant test code,
eliminate code/data duplication, improve design, etc.).
Golden rule: Never write new functionality without a failing test.
EXTENDED DEVELOPMENT CYCLE
Steve Freeman and Nat Pryce introduced outer TDD cycle about
writing a failing acceptance (end-to-end) test before RGR process.
But to make first acceptance test running
you have to implement “Walking skeleton”
beforehand (usually on iteration #0) –
implementation of the thinnest possible
slice of real functionality that we can
automatically build, deploy, and test endto-end.
The smallest number of decisions is made to kick-start TDD
cycle, to allow learning and improving from real feedback.
First, work out how to build, deploy and test, then use that
infrastructure for acceptance tests.
BEFORE YOU START...
Write a list of all the tests you
know you will have to write
into paper ToDo list. To deal
with programming stress
never take a step forward
unless we know where our
foot is going to land.
ToDo list in action
Pick a simplest success test case that will teach you
something and that you are confident you can
implement. Start by testing a variant of an operation
that doesn’t do anything.
TDD PROCESS SMELLS
No green bar in the last 10 minutes.
Not failing first.
Organizing tests around methods, not
Not spending comparable amounts of time on
Using code coverage as a goal.
Not writing the test first.
TESTING BEST PRACTICES
Start testing with the simplest success case.
Treat your test code with the same respect as
your production code.
Refresh ToDo task list when bloated.
Write tests backwards: test name (what to
achieve), call target code (feature entry
point), expectations + assertions (effect should
have), setup/teardown (context).
STAY CLEAN WITH UNGAR’S SHOWER
If you know what to type, type it: always
start from the Obvious Implementation
if you know what it is.
If you don't know how to achieve the result,
Fake It: return 0, return 4 and other
hard-coded test-specific production code are
ubiquitous as TDD starting points.
If you still can't generalize after faking the response, try Triangulation:
write another test which feeds the system other values and expects a
different response. This test, when passing, will ensure there is no
If with triangulation you still don't know how to go on, take a Shower