Test-Driven Development (TDD) in its most dogmatic form (red-green-refactor in micro-iterations) can be tedious. It does not have to be this way! This guide shows a pragmatic approach with integration and unit tests, that works in practice and improves on productivity.
Whenever you notice a new requirement, jot it down as a new scenario/example.
Start writing a feature file. List all usage scenarios you can think of:
Feature: <Concise description of the feature>
<If it is a complex/questionable/very specific feature, add a motivation description or give a good overview.>
Scenario: <Basic usage example, "happy path">
# Add a scenario for each use case. Examples are: error behavior, access rights, contexts, closer looks at parts of the feature
Scenario: ...
(This example uses Cucumber, but the approach works with any integration testing framework.)
If required, add more feature files in the same manner. From these, the reader should understand everything to know about the new feature you're building.
When you're done sketching the feature, start writing out the scenarios one by one. Remember to document motivations or relevant context to a scenario if needed.
Once you are becoming unsure how a scenario will continue, it is time to turn to the code. Remember to finish the test before starting work on the next.
When starting to code, run the current scenario. Write the code that turns the scenario green.
As soon as you're about to write code that is not covered by integration tests, drop to the specs.
Examples:
Unit tests make sure some isolated code works as expected. For each method you're testing, start by listing all usage examples you can think of:
describe <class> do
describe '<method>' do
it '<basic usage example>'
it '<other usage example>'
it '...'
end
end
(This example uses RSpec, but the approach works with any unit testing framework.)
From these, the reader should understand everything to know about that method.
When you're done listing examples, start writing them out. Write an example, then write the code to make it green. Iterate until all Specs are complete and green.
When you're done, return to writing the code. The specced thing now exists, so you can continue making that integration test green.
TDD with integration and unit tests is a process with three abstraction levels:
Integration tests give the code its rough form, whereas unit tests pinpoint selected behavior.
During development, you are frequently changing levels. It may look something like this:
Integration _ ___
Code \____ _____ __/ \__ ...
Unit test \__/ \_/