For sparing time, you end up wasting all time.
A colleague, when first time talked my about XP (more than 10 years ago), said something like "It's wonderfull. You are much quicker. You know it? Beautifull: you write tests, and then ...", and me "tests?!?", "yes, then the system continue to work along time .. tests .." .. and he went on talking about tests as if those were a thrilling job for a programmer. I just do not understand the needs of the test, I was studying and not coding for last 6 years, being at university. But really I should have understood it, few month before I was coding a java icq client, and for knowing where I was and in order to divide development in chunks, I started to write an icq server in C with pthreads and mysql db for linux .. and server was not what I needed, but it take more time than java code!
Tests are for this, spare time. The main functionality for a piece of code is that it does what it is supposed to do, every time, in every scenario. The only requirement for a system is that it does all the functionality in the right way, all time, and in all scenario. Defined all the test, when adding a new functionality, old test have to pass. If there is a bug, it is a scenario that is not in the test cases defined. Define it, and fix the code to pass it.
For example what happen if a new protocol version is supported by a server? Old test have to works as expected. New version has to be detected.
Ok, I convinced myself at least.
I see there are a number of book on writing good test cases, but now I start to write some experience on this field. I want to do more, with less time, and do it better.
Installing PHPUnit and writing tests
The project code should be ready for test, so, in a OO, project class should have method for use in tests, or variant version of some method. For example if a method needs to parse http headers before doing its task, it is needed a default variant NULL that, if setted, is used as headers array.
Then it should be tested if system can parse http headers correctly, I'll do this by a curl call and a test script (that use internal system method) that parse header and print it in a readable format. I can assert on text output and header input.
MakeGood is an Eclipse plugin
after installed I got problems to make it works, I read documentation, but it looked as libraries was missing, and other. In Eclipse it has to be defined a php executable cli and without giving php.ini path it wont works, giving it is not enough in Ubuntu (miss what's in /etc/php5/conf.d). I wrote this
cat /etc/php5/cli/php.ini >~/inieclipse.ini
cat /etc/php5/cli/conf.d/* >>~/inieclipse.ini
and then used ~/inieclipse.ini as cli ini. (not elegant, but rapidity is a requirement, @todo: find how to make it work)
Functionality and tests has to be developed in parallel. It is needed an initial plan (design), for having a working all the architecture, but every time a new functionality is added the corresponding test has to be wrote.
("Design Pattern Explained" - Alan Shalloway & James Trott, propose a good methodology to have an holistic view of the project. Other book suggesting are welcomed)
TDD say to reverse things: wrote test, the implement functionality. For design requirement, such as contract requirement, it is a good practice.
Being every test an isolated case, system state at end of test's running have to be the same as starting state. C'est a dire, if db has data in a state before test run, after test has ran it has to have the old state.
(this is my requirement, I want to see interface and make test, and want to execute test on working copy, maybe not a good practice, but I am learning)
setUp() and tearDown()
For this setUp() and tearDown() are very useful methods, and has to be defined for each test cases, a test case class has to be defined for every different initial state requirement.
DB support (DbUnit)
The system to be tested is naturally complex, so it has a lot of interaction with dbms. For this there is DbUnit for:
1. set initial state
2. test db state during test
3. restore starting state
This are explained in http://www.phpunit.de/manual/3.6/en/database.html
... to be continued