10

Is there a way to write unit tests so that they can be compiled and run both with Delphi and Free Pascal?

There are different unit test frameworks for Delphi and Free Pascal, which causes duplicate work for developers who target both compilers (for example, library and framework developers).

So maybe there is a way, using either the DUnit or the FPCUnit framework and tweak the test case source code (or the framework itself) so that it also works with the other compiler.

So essentially the question is:

  • which framework (DUnit or FPCUnit) can be compiled with both compilers (Delphi and Free Pascal) with as little modifications as possible?

or

  • is there a third framework (Thanks to Arnaud for mentioning TSynTest) which works with Delphi and FPC?
mjn
  • 36,362
  • 28
  • 176
  • 378
  • You ask specifically to write DUnit tests in FPC. That's clearly not possible. But is that what you really meant to ask? Or do you just want to write code in some unit testing framework? My answer took the question at face value. The other answers assumed a more lenient interpretation. Which is it? – David Heffernan Aug 31 '12 at 07:11
  • @DavidHeffernan thank you for pointing this out, I modified the question and added the fpcunit / unit testing tags – mjn Aug 31 '12 at 07:39
  • Good, now I can delete answer which is no longer accurate. Question much better now. – David Heffernan Aug 31 '12 at 07:51

3 Answers3

10

See this very nice blog article - just fresh meat about FPCUnit testing.

In short, as far as I know, and if you compare to DUnit:

  • Most Check*() methods were renamed Assert*();
  • SetUp / TearDown methods are called per-function in both framework;
  • Some other thinks may vary.

So, I think it could be easy to let FPCUnit "mimics" DUnit, by creating a small wrapper class over FPCUnit implementation, to have the same exact methods than with DUnit. So you may be able to share code between the two targets, and even re-use existing DUnit tests. Such a wrapper class is IMHO much more convenient that using {$ifdef FPC} as other suggested here. Conditional compilation tends to make code hard to debug, verbose, redundant and should be used only if necessary.

Another potential solution could be to use other tests frameworks. Our small TSynTest classes are lighter, but I'm currently converting the framework to FPC. So the same exact code could be used with both compilers. It has some features (like optional logging with fine profiling, and full stack strace on failure) which I would miss from DUnit / FPCUnit. It does not have a GUI nor a Wizard but honestly, as I programmer I prefer plain text that I can include in my technical release documentation easily to testify that no regression occurred.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • 1
    Anyway, [`Serg mentioned`](http://stackoverflow.com/a/12209940/960757) his today's blog post ;-) +1 to both... – TLama Aug 31 '12 at 07:47
  • I suggest that your TSynTest running have a non-verbose mode. When I run unit tests, I run the text-mode test-runner and expect output like this `.......` with one dot per passed test, and explicit output (other than a dot) only for failures. Less noise is better. – Warren P Aug 31 '12 at 12:12
  • `TSynTest` is not very verbose by default: it will display one line per test method run. You can also redirect the output. When enabling logging, you have a LOT of content (several 100MB). Of course, if you have only one or two assert per method, it will become verbose. In fact, the test design used is to have smaller private or public methods for testing, then regroup tests within published methods, with explicit names, ready to be displayed. So you can have small granularity, but do not expect one test method per tested class or method. For instance, our mORMot run close to 10,000,000 tests. – Arnaud Bouchez Aug 31 '12 at 16:03
7

Default unit test framework for Free Pascal is FPCUnit, it has the same design as DUnit but different from it in minor details. You can write common unit tests for FPCUnit and DUnit by circumventing the differences by {$IFDEF FPC}. I just tested FPCUnit, it is a usable framework, and blogged about it.

kludg
  • 27,213
  • 5
  • 67
  • 118
4

I just whipped up a sample that works in both DUnit (delphi) and FPCUnit (Freepascal equivalent nearest to DUnit, that happens to ship already "in the box" in lazarus 1.0, which includes freepascal 2.6 ):

A trivial bit of IFDEF and you're there.

unit TestUnit1;

{$IFDEF FPC}
{$mode objfpc}{$H+}
{$ENDIF}

interface

uses
  Classes,
  {$ifdef FPC}
  fpcunit, testutils, testregistry,
  {$else}
  TestFramework,
  {$endif}
  SysUtils;

type
  TTestCase1= class(TTestCase)
  published
    procedure TestHookUp;
  end;

implementation

procedure TTestCase1.TestHookUp;
begin
   Self.Check(false,'value');
end;

initialization
  RegisterTest(TTestCase1{$ifndef FPC}.Suite{$endif});
end.
Warren P
  • 65,725
  • 40
  • 181
  • 316
  • 3
    If you will go further you find other differences, like `TTestCase.CheckEquals` in DUnit is `TTestCase.AssertEquals` is FPCUnit. You need some more {$IFDEF}. – kludg Aug 31 '12 at 06:17
  • 1
    I'd go for a wrapper class to avoid having to litter all my own code with ifdef's... – Marjan Venema Aug 31 '12 at 10:40
  • Exactly. Subclass TTestCase from FPCUnit, and save the unit as TestFramework. Perhaps make whatever else you need from TestUtils and TestRegistry just work. – Warren P Aug 31 '12 at 12:07