From: Subject: Xtreme testing for Delphi programs Date: Sat, 21 Aug 2004 13:07:27 +0300 MIME-Version: 1.0 Content-Type: multipart/related; type="text/html"; boundary="----=_NextPart_000_0000_01C4877F.CED26DB0" X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1441 This is a multi-part message in MIME format. ------=_NextPart_000_0000_01C4877F.CED26DB0 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Content-Location: http://www.suigeneris.org/writings/1999-11-29.html Xtreme testing for Delphi programs
 

This article was published in the Borland Community = web site=20 on November 29, = 1999

3D"Juanco=20 Juancarlo A=F1ez
These articles about = open-source software appeared every Thursday in Borland = Developer=20 News between September 1999 and June 2000.

Xtreme testing for Delphi programs

A standard testing framework for Delphi has been long = overdue. Now=20 there is one and it's even open source.

In my article = on=20 Xtreme testing, I talked about how it could improve the quality of = programs as well as the speed and confidence with which they were=20 developed. For the examples, I used Kent Beck and Erich Gamma's = JUnit=20 open-source testing framework and I wrote the program fragments = using Java=20 -- a language I'm comfortable with. But those who know me from = previous=20 writing gigs or my once-frequent postings in online forums know = that I've=20 long been a Borland Pascal programmer. My online buddies are = probably=20 wondering why I didn't write the examples in Object Pascal. The = reason is=20 that I discovered Xtreme testing only recently, and, as far as I = know,=20 there are no testing frameworks available for Delphi.

But we're about to change that.

I've been choosing the latest version of Borland's Pascal as = the best=20 solution to most of my programming needs for 15 years now. The = reasons are=20 varied. The tool's suitability to the kind of applications I've = been=20 developing is one reason. Its overall quality is another. Not to = mention=20 its blazing instant-feedback speed. A large reason has been the = community=20 of developers that has gathered around the tool.

I met that community when I joined CompuServe and the BPASCAL = forum=20 back in 1993. BPASCAL quickly became an invaluable asset. The = forum was=20 filled with excellent questions, prompt answers, expert advice, = and loads=20 of useful source code. Examples, workarounds, patches, libraries,=20 frameworks, and even complete applications were available for = download and=20 free use. The forum's motto was "Don't pay back -- pay forward," = and these=20 guys took it seriously. I started contributing advice and source = code as=20 soon as I was confident enough to do so, and eventually became = expert=20 enough to start writing about Delphi for trade publications -- but = that's=20 another story.

Even after all these years I have never felt that I had managed = to=20 fully pay back -- er, forward -- all the help. That's the reason = for this=20 contribution: DUnit, a port of the JUnit Xtreme testing framework = to=20 Delphi.

Porting from JUnit

The original JUnit framework is extremely easy to use and very=20 effective. I wanted the Delphi port to be as good.

To speed up the port, I decided to translate the classes and = interfaces=20 in JUnit almost literally. It was a compromise that required heavy = use of=20 method overloading, which means that DUnit won't be usable with = versions=20 of Delphi prior to version 4.

I made another compromise. I could translate the methods in = JUnit=20 almost literally if I used the Delphi port of the Java collections = library=20 that I had begun implementing, so that's exactly what I did.

These two decisions let me do the port in a single afternoon = and=20 resulted in a framework that I find very easy to use. But the=20 implementation relies heavily on interfaces and iterators -- = idioms seldom=20 used by Delphi programmers. Although the first idiom is fully = supported by=20 Delphi, most programmers reserve it for dealing with COM and = ActiveX=20 objects. Interfaces provide the advantage of memory management by=20 reference counting, so a little work up-front with interfaces = translates=20 into much less code to write. You do have to be careful with some=20 interface implementation issues. For example, a loop with = references to=20 interfaces will make it impossible for Delphi to reclaim the = memory used.=20

The second idiom is common in Java and C++ programs, but may be = unfamiliar to Delphi programmers. Iterators enable you to write=20 implementation-independent loops that process the objects = contained in a=20 collection. JUnit uses iterators, so DUnit does too.

Classes that test classes

To apply DUnit to your Delphi programs, you write a descendant = of the=20 class TTestCase for each test case you want to apply to a unit. I = decided=20 to apply DUnit to the collections library used in its own = implementation.=20 To avoid circular unit references, I had to declare the test case = classes=20 in the main program (DPR) file, but I recommend that in general = you place=20 the test classes inside the units they test. Doing so will let you = test=20 protected and private methods in addition to the public and = published=20 ones.

This is the class declaration for a simple test case:

type
 =20 = TListTests =3D class(TTestCase, ITest)
  publ= ished
    =20 = // published, so we get RTTI;
  &nb= sp; =20 = // virtual, so the compiler 
  &nbs= p; =20 // doesn't eliminate them;
    =20 = procedure testEmptyArrayList; virtual;
   &nb= sp;=20 = procedure testEmptyLinkedList; virtual;
   &n= bsp;=20 = procedure doEmptyTests(list :IList);
    = ;=20 procedure testFailure; virtual;
    =20 procedure testError; virtual;
end;


The first two methods test several conditions on arrays and = linked=20 lists. The third procedure is a utility used by the preceding = routines.=20 The last two methods generate a test failure and an exception=20 respectively, to make sure DUnit responds properly when errors are = detected. The test methods must be declared within a published = section so=20 that Delphi generates runtime type information for them and DUnit = has=20 access to method names at runtime. Here's part of the = implementation of=20 doEmptyTests:

=

procedure TListTests.doEmptyTests
 (list: ILis= t);
var
  i :IIterator;
begin
  asse= rt('isEmpty', list.isEmpty);
  assertEquals('size',&nbs= p;0, list.size);
  assert('iterator at end',&= nbsp;
   =20 = not list.iterator.hasNext);
  list.add('anItem');
&n= bsp; assertEquals('size', 1, list.size);
  //= ...
=20

Yes, writing the test cases is that easy. Each line in the test = method=20 checks (asserts) a condition that should be true if the tested = code is=20 working properly. DUnit provides several different assertXXX = methods to=20 make writing tests easier.

Pulling it all together

To assemble all the test methods into a single test suite, you = write a=20 function like this:

=

function suite :ITestSuite;
begin
  re= sult :=3D TTestSuite.Create;
  result.addTest(TLis= tTests.Create(
   =20 = 'testEmptyArrayList'));
  result.addTest(TListTests.Create(<= BR>   =20 = 'testEmptyLinkedList'));
  result.addTest(TListTests.Create(=
   =20 = 'testFailure'));
  result.addTest(TListTests.Create(
&nbs= p;  =20 'testError'));
end;

Finally, you run the tests in console mode with a single = statement in=20 the main program block:

begin
  DUnit.runTest(suite, = true);
end.
=20

Oops! Two bugs in the collections library surfaced while I was=20 executing the tests. So the framework has already paid for the = effort I=20 invested in it. After fixing the bugs and running the tests again, = the=20 output looks exactly as expected:

=

DUnit: Testing.

...F.E

Time: 0.0

= FAILURES!!!
Test Results:
Run: 4 Failures: 1&nb= sp;Errors: 1
There was 1 error:
1) TListTe= sts.testError: EAbort: 
 =20 = Raised exception on purpose
There was 1 = failure:
1) TListTests.testFailure: 
 =20 = AssertionFailedError: Failed on purpose

Press = <RETURN> to continue.
=20

A license to test

What are the licensing terms for DUnit? In open source = development,=20 when you enhance, fix or port someone else's code, it is customary = to:=20

  • Give as many rights to the original software as the original = authors=20 did.=20
  • Give the same rights to your contributions (some licenses, = such as=20 the GNU GPL, require that you to do this).=20
  • Give credit to the original authors for their work.=20
  • Preserve all disclaimers made by the original authors, in = particular=20 those about lack of warranty and protection from their names = being used=20 for promotion without authorization.

The license to the original JUnit is very flexible, so I made = the=20 license to DUnit almost an exact copy of it. The part about your = rights=20 reads like this:

Permission to reproduce and create derivative works from the = Software=20 ("Software Derivative Works") is hereby granted to you under the = copyrights of [...] (THE AUTHORS). The authors also grant you = the right=20 to distribute the Software and Software Derivative Works.=20

Next steps

As it stands, DUnit lacks any documentation. If you can read = Java code,=20 then the documentation that comes with JUnit is probably = sufficient.

At this time the following still needs to be done:

  • Create a GUI interface to the framework like the one JUnit = has.=20 Given Delphi's GUI capabilities, this shouldn't take more than = an hour=20 or so.=20
  • Use Delphi's RTTI to build a test suite automatically by = gathering=20 all the methods with names that start with "test." JUnit does = this, and=20 the feature is very useful. I'll leave this task to someone = else.=20
  • Translate JUnit's excellent documentation and examples to = Delphi.=20

If you'd like to contribute to the DUnit project, please do so. = But try=20 to refrain from sending me suggestions. What I think should be = done in=20 DUnit I will likely do, time permitting. As Linus Torvald says, = I'd rather=20 you "show me the source code!"

Oh -- the source code! You can download the source code to the = latest=20 version of DUnit from my always-under-construction Web site: http://www.suigeneris= .org/dunit/index.html.=20 I hope you find this small testing framework useful. If you do, = please=20 forget about expressing thanks. Pay forward.

Originally written for In Publishing=20 LLC
Copyright =A9 1999 Inprise Corp.
=


------=_NextPart_000_0000_01C4877F.CED26DB0 Content-Type: image/jpeg Content-Transfer-Encoding: base64 Content-Location: http://www.suigeneris.org/writings/images/biojuanco.jpg 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 ------=_NextPart_000_0000_01C4877F.CED26DB0 Content-Type: text/css; charset="iso-8859-9" Content-Transfer-Encoding: 7bit Content-Location: http://www.suigeneris.org/writings/writings.css @import url( ../style/suigeneris.css ); H1 { FONT-SIZE: 120% } H2 { FONT-SIZE: 100% } P.poem { FONT-SIZE: 110%; TEXT-INDENT: 0px; FONT-FAMILY: Times, serif } ------=_NextPart_000_0000_01C4877F.CED26DB0 Content-Type: application/octet-stream Content-Transfer-Encoding: quoted-printable Content-Location: http://127.0.0.1:1048/js.cgi?pa&r=32391 var blockedReferrer =3D 'blockedReferrer'; NS_ActualWrite=3Ddocument.write; // Popup Blocker --> RanPostamble=3D0; NS_ActualOpen=3Dwindow.open; orig_setTimeout =3D window.setTimeout; function NS_NullWindow(){this.window;} function nullDoc() { this.open =3D NS_NullWindow; this.write =3D NS_NullWindow; this.close =3D NS_NullWindow; } function NS_NewOpen(url,nam,atr){ if((nam!=3D'' && nam=3D=3Dwindow.name) || nam=3D=3D'_top'){ return(NS_ActualOpen(url,nam,atr));} obj=3Dnew NS_NullWindow(); obj.focus =3D NS_NullWindow; obj.blur =3D NS_NullWindow; obj.opener =3D this.window; obj.document =3D new nullDoc(); return(obj); } function NS_NullWindow2(){this.window;} function NS_NewOpen2(url,nam,atr){ if((nam!=3D'' && nam=3D=3Dwindow.name) || nam=3D=3D'_top'){ return(NS_ActualOpen(url,nam,atr));} return(new NS_NullWindow2()); } function op_stop() { NS_ActualOpen2=3Dwindow.open; = window.open=3DNS_NewOpen2; } function op_start() { window.open=3DNS_ActualOpen2; } function noopen_ST(one,two) { = return(orig_setTimeout("op_stop();"+one+";;op_start();",two)); } function noopen_load() {=20 op_stop(); if(orig_onload) orig_onload(); op_start(); } function noopen_unload() { op_stop(); if(orig_onunload) orig_onunload(); = op_start(); } function postamble() {=0A= =0A= if(!RanPostamble) { RanPostamble=3D1; orig_onload =3D window.onload; orig_onunload =3D window.onunload; window.onunload =3D noopen_unload; window.onload =3D noopen_load; window.open=3DNS_ActualOpen; } } window.setTimeout =3D noopen_ST; window.open=3DNS_NewOpen; ------=_NextPart_000_0000_01C4877F.CED26DB0--