I think concepts like this are often best explained using examples. Let's take a very simple piece of software develeopment :- a
Java class to parse a line of comma-separated text into an array of Strings.
If I assume an XP-style process, the
first thing to do is to produce unit tests. This may seem wierd, but bear with me. I'll write the unit tests as fragments of code which could be used by
JUnit (a unit-test framework used by many XP/Java programmers).
OK, so what would be the simplest unit test to start with? How about checking that an empty line generates an empty array?
This shows several very important things about XP unit tests.
1. Unit tests are just code. For XP to achieve the full speed and quality of code, you need to be able to run the whole unit test suite quickly and often. So use a unit-test framework which lets you write executable tests.
2. Writing unit tests as code has already made me think about what interface my little thing should provide, and what to call it. Even though neither the source code or the class file exists yet, it has a name, a constructor and a method. Design has already started!
3. Always start as simple as possible. I've not worried at all about where the class comes from, how it's loaded, what other methods it provides, what interfaces it implements, what happens if I give it any other input... I'm only testing one thing - how it behaves when given an empty
string.
4. A single "unit test" can be several "asserts". In this case, in order to check that the length is 0, I also check that the returned array is not null.
5. This test will fail. In fact it won't even compile! But that's OK. It's what I expected when I wrote it. So now, having written the test, I can proceed to the next stage of this little task; implementation.
XP recommends wrinting the simplest possible implementation which passes all the tests so far, so let's write a simple class to do just that.
If I compile the code and the test case, then run it I should get an indication that 1 of 1 tests pass. Excellent, the first iteration is complete. If I get any errors, either at compile time, or run time, I fix the code until all tests pass, then move on.
Now what's the next unit test? How about "if the line has only one column, return it"? Off we go again; add another unit test:
This looks good, but if you look closer, the principle of
Once and Only Once has been violated. A new LineParser is created in
both test cases. So let's refactor a little. Luckily, JUnit provides a place to put common initialization code; the method setUp(), so our whole test suite now looks like:
Now we get to update the code to implement the new functionality. because the original unit test is still in the test suite, it will make sure that our new change still works for empty strings. So here's the new code:
I guess you are getting worried by now. Most experienced programmers are already trying to solve the whole problem, but this is the very heart of XP. We
don't know what the next unit test will be, so we should not attempt to solve it. XP is based on being able to deliver each new functionality as soon as possible, and allowing the customer to cancel development
at any stage and always have a working version which implements all the features so far. So the extra 20-30 minutes it might take to sort out how to use a StringTokenizer, how to decide how many array slots to create and so on would be wasted time, if the customer only wants files with no words or one
word per line, This change only took about 1 minute, so it's 20 times cheaper!
I hope you are getting the idea of how this works. we've already done two iterations of test-driven XP development in less time than it takes to read this.
Now some excercises:
1. Find and install JUnit (hint, try
http://xprogramming.com/) 2. Compile and run the above tests, and make sure they work.
3. Add a new unit test for "hello,world" making ["hello" "world"]
4. Update the code to make it pass the new test as well as the old ones. (hint,
you should be getting closer to a general case with every change from now on. Remember to keep the code as simple as possible, refactor as necessary)