Testing the World Away: Recovery mission

I was recently reviewing the DUnit website and I noticed there is a broken link to an article titled “Testing The World Away”. It was written by Will Watts for QBS Software. November, 2000.

I said “OK, maybe the article was relocated somewhere else in the QBS Software website”; so I tried a custom Google search "Testing the World Away" site:qbssoftware.com. As you can see the article was either banned from Google or removed completely from the QBS Software website.

Once again I said “OK, maybe there’s a copy of the article somewhere else on the Internet” and I tried a second custom Google search "Testing the World Away". At this point I convinced myself that the article was gone for good.

I am a curious guy, so I tried one final thing: I looked up the broken link[1] in the Internet Archive website and wallah!, they came with an archived version of the article.

I have shared below a copy of the article so that we can take a look. As I said, this article is not mine, and if the author(owner) at some point request me to deleted it from my blog, I will do so.

[1] http://www.qbss.com/html/news/news_body.asp?content=ARTICLE&link=368&zone= 

Testing the World Away (01 November 2000)

Testing the World Away

The software methodology of the hour is Kent Beck’s ‘Extreme Programming’. Mr Beck is a Smalltalk programmer by trade and, I think, a bit of a lad by inclination (evidence: the bibliography of his book Extreme Programming Explained, as well as citing standards such as The Mythical Man-Month and Design Patterns, also recommends Cynthia Heimel’s Sex Tips for Girls. Right on!). I find some of his ideas unconvincing. Pair Programming for example, where one programmer sits at the keyboard and works while the other does something else - possibly flower-arranging, my concentration lapsed at this point in the text as I tried to imagine any manager I’ve met who would permit this exciting way of increasing his costs - seems too beautiful and delicate for our mortal coil. On the other hand his approach to testing, and the free libraries based on his design that are around to back it up, comes much nearer to hitting, as I suppose Ms Heimel might put it, my programming G-spot.

Mr Beck’s idea is that as you write each bit of code, you should also write a little test to go with it. As the project develops, the library of tests builds up in parallel. After each alteration or addition, you rerun the test suite to discover if you have broken anything. One of the rules - and I think it is an important one - is that the test suite must be able to run all the way through, pass or fail, without operator intervention. So although it is a chore to write the tests, the effort put in is ‘banked’, and it costs very little to rerun them - with the consequence that they do get rerun.

Mr Beck has had brushes with those GUI automated tools that record keystrokes and mouse-clicks into some sort of script and then let you play your actions back at the application to be tested and verify its responses. These look like they are going to do the job from the description on the packet but in practice, as Mr Beck correctly observes, they are not very robust. Remove one edit box, or merely nudge it three pixels to the right, or change the screen resolution - suddenly the whole thing falls flat on its face. Testing code, he decided, should be written at the same level and in the same language as the stuff to be tested.

Tests also need structure. One needs to see results presented in a consistent way, to be able to select specific tests to run and so on. To this end, Mr Beck wrote a library of Smalltalk classes - a framework - called ‘SmalltalkUnit’ or ‘SUnit’. Later on he collaborated with no less than Erich Gamma to produce a Java version called ‘JUnit’. The idea ‘took on’, and now there are versions for an impressive range of languages including C++, Eiffel, Objective-C, Perl, Python, Visual Basic and even Visual Objects. You'll find them all listed at http://www.xprogramming.com/software.htm. If you are familiar with my language prejudices, you will be unsurprised to learn that I am going to discuss a Delphi language version called DUnit. Originally ported from the Java version by Juancarlo AƱez, this library is now maintained on an Open Source basis by the DUnit group at SourceForge:

https://sourceforge.net/projects/dunit/. This library makes heavy use of function overloading, so you’ll need Delphi 4 or later to play with it.

Who DUnit?
Figure 1 shows a suite of DUnit tests that have been run using the library’s GUI interface. The top pane lists all the tests available. These are organised in a hierarchy: a suites of tests may contain either individual test cases or other suites - a Composite pattern. In the part of the hierarchy visible, I have set up a suite called ‘SFW COM Library tests’ that, in turn, contains suites subdivided by the class being tested. The TTestDoubleChannel suite operates on a class called TDoubleChannel, and below TTestDoubleChannel are tests on individual methods. There are checkboxes to switch individual tests and parts of the hierarchy on and off; these interact with some useful buttons at the bottom of the dialog to allow speedy selection of all or part of the suite.

Each test is colour-coded by the result of the last run. Green, obviously, indicates success; magenta a ‘failure’, that is that an unexpected result was obtained; red, an ‘error’, that the test threw an exception. The lower pane lists all the failures and errors together with descriptive messages. In between the two panes are progress bars indicating progress through the test suite and success rate.

Figure 2 shows DUnit’s text mode version after running the same test suite as Figure 1, and I hope that you can see it has produced the same results. Although lacking the eye candy and versatility of the GUI test runner, this console version requires no interaction and sets its exit code non-zero on failure. This makes it ideal for placing in a make file, or incorporating into an automated testing procedure. By the way, to make my test suite code run as a console application, I substituted one .DPR file for another - about 10 seconds’ work.

How it works

The key class in DUnit’s framework is TTestCase. All the actual testing code is placed in classes that you derive from it. It’s easiest to see how this works with a snippet of code. Figure 3 shows a trivial example of a program that tests 1 + 1 = 2.

First look at the Project1TestCases.pas unit. TTestCaseFirst is derived from TTestCase, adding one published method testFirst. Three features of this method are important: that it is a parameterless procedure, that it has public scope, and that its name begins ‘test…’. These features enable DUnit to discover and run the method without the need to call it explicitly in hand-generated code. It is sufficient to declare a method of a TTestCase-derived class that follows these rules to get it run.

The implementation of testFirst is a single line: I ‘assert’ that 1 + 1 = 2. (Old Delphi hands and practitioners of design-by-contract may be raising their eyebrows at this strange use of Assert. Please bear with me, explanations and excuses will follow in due course.)

At the bottom of Project1TestCases.pas, in an initialization section, is the call registerTest('', TTestCaseFirst); which registers TTestCaseFirst with the framework. The first parameter is the ‘path’, it controls where a test case appears in the hierarchy. By supplying an empty string I am placing it below the root node.

The project file Project1Test.dpr references DUnit library units TestFrameWork and GUITestRunner as well as Project1TestCases.pas. A single line replaces the standard Delphi GUI project code: GUITestRunner.runTest(TestFramework.registeredTests);

This creates and displays the GUI interface shown in Figure 1. And that’s it. To add further arithmetic tests, just write extra test… methods, for example

procedure TTestCaseFirst.testSecond;
begin
  Assert(2 + 2 = 5, 'Oops!');
end;

This mistake will be flagged as a magenta-coloured failure when it is run.

In reality one uses DUnit on classes rather than trivial arithmetic. Instances of classes can be placed as member data in the TTestCase-derived class, and two virtual methods, SetUp and TearDown, can be overridden to create and destroy them around each test method. Figure 4 sketches how this is done. Note that SetUp is called before, and TearDown after, each test method. This isolation of the test methods from each other is deliberate - you shouldn’t build a sequence of tests where one method is dependant on those called before.
I mentioned DUnit’s ability to build up suites from multiple test cases. This is accomplished using the TTestSuite class:
Suite := TTestSuite.create('A suite');
Suite.addTests(TTestCaseFirst);
Suite.addTests(TTestCaseMyClass);

The populated suite can then be passed to registerTest as before.

All About Assert

It’s time to own up to a problem with DUnit. The library’s use of the Assert function to check the test conditions is rather perverse. Assert already has a well-understood role in Delphi code, and this isn’t it. How did it get there? Well, you will recall that DUnit is a port of a Java library called JUnit and the Java language, I am informed, doesn’t have an Assert in the C++/Delphi sense. Unfortunately the ‘Assert’ name was carried across with the rest of JUnit. An easy mistake to make:  it has also happened to the people doing a C++ version of JUnit.

However, there is a move afoot among the DUnit developers to change the function's name, probably to Check, and also to add a family of useful overloaded methods with names like CheckEqual, CheckNotEqual and so on. With luck this will have gone through by the time you read this.

DUnit is very much work-in-progress, and there are a number of interesting additions and enhancements coming into view. Two add-ons have just been released - one standalone, one integrated with the IDE enhancer CodeRush - which will generate skeleton test case code from the declaration of a class that is to be tested. As well as extra facilities for test repetition and set-up that I have not covered here, there are also plans to add special support for databases, multi-threading and GUI testing.

No technique can stop testing from being a fag. But I have found that the accumulation of a permanent test suite, and the improved confidence in my code developed in this way make DUnit’s use worthwhile. Go on: pull it down and have a go!

Will Watts is a programmer and occasional journo who lives in Chiswick. To his pleasure, his Snobol column in Developers Review has not, as far as he knows, been nominated for the Worst IT Journalism 2000 Award.

Books:
Extreme Programming Explained by Kent Beck, pub Addison-Wesley, ISBN 0-201-61641-6. Mr Beck’s philosophy of software development.
Refactoring - Improving the Design of Existing Code by Martin Fowler et al, pub Addison-Wesley, ISBN 0-201-48567-2. Includes good description of JUnit.

1 comment:

  1. Gosh - that's an old piece. You are welcome to keep it here, if you think it is useful.

    Will Watts
    Still a programmer and occasional journo who lives in Chiswick

    ReplyDelete