Test Driven Development
This is a presentation Francis put together for a client who are a PHP shop. He wanted to show them how to take the ideas he had picked up from the Rails community and make them work for them.
Blog posts on TDD
Why do TDD?
- It's no more effort once you've got the habit. You were going to test what you wrote anyway, right? Now that effort isn't thrown away, but kept in the code base permanently. Lots of people say the see the logic of TDD but "can't afford the time". Really? You were going to test it all by hand or with a harness weren't you? So what can't you afford?
- It gives you a parachute. If you need to make a big change, e.g. a new library version has changed its API, you can make sure your code behaves the same as it always did.
- No more fix n' fail n' fail again. You make a small change that has unforseen consequences far away because of a dependency which can quickly baloon into a nigthmare - now you will know before deploy because these tests will fail.
- You know what the system is supposed to do. In the absence of up to date documentation the tests allow you to work out what the correct behaviour is and verify it still happens after changes. Up to date documentation is expensive and rare. Freezing the existing knowledge as you go along is relatively cheap.
- Your code is better written. A useful side effect of habitual TDD is smaller, more focussed methods rather than honkin' big lumpsa code ®. Small methods are easier to test and verify so you tend to write them that way.
- Bugs don't come back. Bug arrives, test is written to expose bug, bug is fixed, code goes out. Bug stays fixed.
- Code is written twice. Tests test behaviour, not internals. When you are a beginner it's very easy to write a stub for every line in the method you are testing and effectively writing everything twice.
- Tests can be brittle. XML responses, for example, are relatively hard to test and you quite often end up pattern matching. A small change of case, for example, can break a test but still work for real.
- External dependencies can change. Often external services are stubbed out in testing frameworks for speed and repeatability. A third-party change can give you production grief. You need to write some tests that go end-to-end and exercise everything, but just take the general case where everything suceeds. Test the errors with stubs and mocks. We also tend to write end-to-end tests using tools like Selenium, that exercise the whole application in a browser, but not every error condition - you should have already done that.
- Some people also claim that TDD is hard to do for desktop GUI programs. If Microsoft can do it so can you. At the very least you can test the service wrappers your app uses.
It is not a universal panacea, for example testing race conditions and other such things that cause servers to overload would have to be done with some kind of load runner software. But at least you know it does what it says on the tin.