Welcome to Duncan White's Practical Software Development (PSD) Pages.

I'm Duncan White, an experienced and professional programmer, and have been programming for well over 20 years, mainly in C and Perl, although I know many other languages. In that time, despite my best intentions:-), I just can't help learning a thing or two about the practical matters of designing, programming, testing, debugging, running projects etc. Back in 2007, I thought I'd start writing an occasional series of articles, book reviews, more general thoughts etc, all focussing on software development without all the guff.

See all my Practical Software Development (PSD) Pages

picture of D. White

Testing and Development part 4

Generating a Printable form of a Stack

Meta-tests: designing a Little Language

Let me leave you with a final thought: applying my core principle of ruthless automation even further, we could autogenerate such stack tests - and their correct answers - by designing a little language which defined a sequence of operations to perform, and a trivial "interpreter" in a scripting language like Perl, which does three things:

  1. Simulate a stack, obeying the instructions one by one and hence calculating the correct checks and answers at each stage.
  2. writes the corresponding C test program for us, embedding the correct checks as it goes! This is an example of the Pragmatic Programmers' advice to write Programs that write Programs. (see my Review of the Pragmatic Programmer here).
  3. compiles and executes the automatically generated C test program for us, telling us if any fail!

Suppose we choose to define the string:

	20 30 -
to represent the sequence of stack operations and checks:

In this notation, our whole test5 test case is equivalent to:

	20 30 45 - - -

This would be trivial to write (in Perl) - half an hour's work or less, by my estimation! Maybe I'll cover this in a future "little language" article.. watch this space!

Summary: Give TDD a try!

So, what has this article shown? I think TDD is a very interesting approach, I like the emphasis on strong and automatic testing and I really love the idea of building a test, expecting your code to fail, running the test, confirming that your code fails the test, and only then trying to write the missing functionality. This gives a really strong focus to your development - you're not designing and implementing thousands of lines of code that you think you may need later, instead you're writing exactly what you need to make your latest test pass.

By the way - if you were wrong and your code already passes the new test, this is valuable (and surprising) information that you'd want to investigate carefully. How would you ever know this without TDD?

There is the question: when do you stop developing in TDD? - after all, you can always write more tests. Presumably you have some higher level goal (specification) in mind as well, and you can therefore tell once you've added all the features required by the spec and tested that they work by TDD. Of course, the flexibility of TDD allows you to change your mind months or years later and add some new features, driven by new TDD test cases.

You wouldn't want to stop developing before you had good test coverage - until you are convinced that your tests are, in principle, deep and thorough enough to cover all special cases in your code (bearing in mind that no amount of testing can prove correctness).

Another question emerged in Part 3 when we noticed that we only tested stacks up to depth 1, and then deliberately built a "stack of one element" that minimally satisfies (satisfices) our test suite. We did this primarily to point out the incompleteness of our test suite. But at that point, I observed:

This is one thing that concerns me about TDD - if the tests are actually driving development, it's arguable that the joke stack of one element is a correct solution at this point.

Then I concluded:

However, I hope that noone would ever write such a stupid implementation, even as a stepping stone - except to make a point.
Is this conclusion safe to make? I think so, because it seems obvious that a "stack of elements" must store a collection of many elements. Alternatively, one could argue that it doesn't matter if a programmer initially implements a "stack of one", because later they will write a "2 deep stack" test, see it fail and then generalise.

Finally, this last part of this article points out a surprising way in which the argument from my very first PSD article (every ADT needs a display_as_str operation) is extremely useful in TDD. As I said above:

One of the simplest ways to check that an ADT object is correct after a series of operations is to generate the as_str form of the final object and then compare the actual string result against the known correct (hand-built) printable form.

Thanks for reading this far! If you have any comments, I'm very interested in hearing from you..

Back to part 3 of this article Back to PSD Top
Written: March-June 2013