2

What tools would you recommend for unit testing in Delphi.
I've used FastMM4 for memoryleak testing.
And MadExcept, both rule, but it doesn't help me test the logic in my programs.
I would like some alternatives, so don't all rush to suggest DUnit :-).

Any suggestions?

Johan
  • 71,222
  • 23
  • 174
  • 298
  • 1
    Duplicate of http://stackoverflow.com/questions/18291/unit-testing-in-delphi-how-are-you-doing-it – LachlanG Apr 12 '11 at 23:42
  • See also Fitnesse for Delphi - http://stackoverflow.com/questions/91826/fitnesse-for-delphi-2006-delphi-2007-delphi-2009 – mjn Apr 13 '11 at 15:09

3 Answers3

9

The most commonly used is DUnit. It's actually included in modern versions of Delphi but if your version doesn't come with it you can download it from Sourceforge.

David Heffernan
  • 572,264
  • 40
  • 974
  • 1,389
  • Although I'm not 100% sure when it started, DUnit was definitely included in D2005 and later, so the OP should have it already. – Michael Madsen Apr 12 '11 at 22:36
  • Yes, got DUnit, was hoping some better silver bullet was around somewhere :-) – Johan Apr 13 '11 at 06:37
  • @Johan: are you looking for a unit testing framework or for a more comprehensive testing framework? Unit testing has its scope and "philosophy". If you're looking for something that can test your application with a different approach there are many other solutions, i.e. AutomatedQA TestComplete or HP Mercury Interactive. –  Apr 13 '11 at 10:44
  • Cool thanks, never heard of these, will be sure to check them out. – Johan Apr 13 '11 at 10:49
8

DUnit comes with D2007.

-->File -->New -->Other

Select Unit Test from the dialogue that pops up.

There are a couple of good demo videos on it's use, I'll see if I can dig one up.

This is a pretty good one and others come up on the right:

http://www.youtube.com/watch?v=nyZnfxDqThE

7

You could take a look at the unit testing classes available in our SynCommons open source unit. It's used in our Open-Source framework for all regression tests. It's perhaps not the best, but it's worth taking a look at it. See http://blog.synopse.info/post/2010/07/23/Unit-Testing-light-in-Delphi

In the up-to-come 1.13 version, there is also a new logging mechanism with stack trace of any raised exception and such, just like MadExcept, using .map file content as source.

It's now used by the unit testing classes, so that any failure will create an entry in the log with the source line, and stack trace:

C:\Dev\lib\SQLite3\exe\TestSQL3.exe 0.0.0.0 (2011-04-13)
Host=Laptop User=MyName CPU=2*0-15-1027 OS=2.3=5.1.2600 Wow64=0 Freq=3579545
TSynLogTest 1.13 2011-04-13 05:40:25

20110413 05402559 fail  TTestLowLevelCommon(00B31D70) Low level common: TDynArray "" stack trace 0002FE0B SynCommons.TDynArray.Init (15148) 00036736 SynCommons.Test64K (18206) 0003682F SynCommons.TTestLowLevelCommon._TDynArray (18214) 000E9C94 TestSQL3 (163) 

The difference between a test suit without logging and a test suit with logging is only this:

procedure TSynTestsLogged.Failed(const msg: string; aTest: TSynTestCase);
begin
  inherited;
  with TestCase[fCurrentMethod] do
    fLogFile.Log(sllFail,'%: % "%"',
      [Ident,TestName[fCurrentMethodIndex],msg],aTest);
end;

The logging mechanism can be used to trace recursive calls. It can use an interface-based mechanism to log when you enter and leave any method:

procedure TMyDB.SQLExecute(const SQL: RawUTF8);
var ILog: ISynLog;
begin
  ILog := TSynLogDB.Enter(self,'SQLExecute');
  // do some stuff
  ILog.Log(sllInfo,'SQL=%',[SQL]);
end; // when you leave the method, it will write the corresponding event to the log

It will be logged as such:

20110325 19325801  +    MyDBUnit.TMyDB(004E11F4).SQLExecute
20110325 19325801 info   SQL=SELECT * FROM Table;
20110325 19325801  -    MyDBUnit.TMyDB(004E11F4).SQLExecute 

Here the method name is set in the code ('SQLExecute'). But if you have an associated .map file, the logging mechanism is able to read this symbol information, and write the exact line number of the event.

Note that by default you have time and date written to the log, but it's also possible to replace this timing with high-resolution timestamps. With this, you'll be able to profile your application with data coming from the customer side, on its real computer. Via the Enter method (and its auto-Leave feature), you have all information needed for this. ;)

Like this:

0000000000000B56  +    TTestCompression(00AB3570).000E6C79 SynSelfTests.TTestCompression.TestLog (376) 
0000000000001785  -    TTestCompression(00AB3570).000E6D09 SynSelfTests.TTestCompression.TestLog (385) 

I still need to write some tool to compute the profiling, but there is already a dedicated TSynLogFile class able to read the .log file, and recognize its content.

The first time the .map file is read, a .mab file is created, and will contain all symbol information needed. You can send the .mab file with the .exe to your client, or even embed its content to the .exe. This .mab file is optimized: a .map of 927,984 bytes compresses into a 71,943 .mab file.

So this unit could be recognized as the natural child of DUnit and MadExcept wedding, in pure OpenSource. :)

Additional information is available on our forum. Feel free to ask. Feedback and feature requests are welcome! Works from Delphi 6 up to XE.

Arnaud Bouchez
  • 40,947
  • 3
  • 66
  • 152