Welcome to Part 4 of this review of the Pluralsight course Introduction to Testing in Java by Richard Warburton.
Test Driven Development
Why TDD?
TDD uses tests to drive the development effort and encourage good design. Richard says there’s much more to software development than writing working code, such as:
How to design your code?
How to encourage testing?
YAGNI – You Ain’t Gonna Need It
We hear the old adage “You can take a horse to water but you can’t make it drink”.
It’s up to developers to write unit tests, and with TDD they write them before the implementation.
With regards to YAGNI, we have this quote from Ron Jeffries:
“Always implement things when you actually need them, never when you foresee that you need them.”
So we can view the goal of TDD as the incremental production of well designed and tested code.
What is TDD?
We can think of TDD as a workflow:
Red: Write a failing test
Green: Passing Implementation
Refactor
Richard says the refactor step is very important. We need to tidy up our code as we go so that we don’t create problems for ourselves in the future.
What is TDD? (Live Coding)
One of the classic beginner exercises for TDD is the leap year kata.
Emily Bache does this in Python in her course Coding Dojo: Test Driven Development
In this lesson Richard explains there are three things that we need to think about:
1. A year is a leap year if it is divisible by four
2. But years divisible by 100 are not lear years
3. Except years divisble by 400.
(This is assuming we are using the Gregorian calendar)
By the end of this lesson we have the following tests, which have driven our design:
leapYearsAreDivisibleByFour
normalYearsAreNotDivisbleByFour
leapYearsAreNotDivisibleByOneHundred
leapYearsAreDivisibleByFourHundred
Triangulation
Richard says the LeapYear problem has unusually specific tests. This makes it a very good candidate for test driven development.
In the real world requirements are often a lot less precise.
It helps to come up with examples that we can test. Once we’ve done that, how can we derive a more general testable algorithm?
The term Triangulation comes from the Navy: taking two points on the horizon, measuring their distance and using Euclidean geometry to calculate position.
Triangulation (Live Coding)
In this lesson we implement a wordwrap class, and we’re starting off with a vaguely worded specification:
“A method that breaks words on a specified space with a new line, like a word processor would”
We start with the test lineShouldWrapIfOverLineLength
.
As we write this test we decide the user should supply both the text string and the line length to our method.
We assert that the result includes the new line character.
After this first test passes and we’ve refactored, we write shortLinesShouldNotWrap
and assert that the input string is unchanged.
Our third test is longerLineShouldWrapTwice
, and we initially implement a naive solution for this.
By the time we write the evenLongerLinesShouldWrapThrice
, we’re increasingly aware that we need to find a generic solution to this problem.
We can do this using a while loop.
The final test is longLinesDontHaveToBeAMultipleOfLineLength
.
Summary & Variants
Richard encourages you to practice TDD. He also introduces the two schools of TDD: Classic and Mockist/London School of TDD.
We haven’t covered mocks yet, but will do in the next module.
Also see Is TDD Dead? Really???