VSoft Technologies Blogs

rss

VSoft Technologies Blogs - posts about our products and software development.

But, we have DUnit....

Unit Testing in Delphi is not new, the DUnit framework has been around for many years. So why create a new unit test framework? My motivation for creating a new framework was partially frustration with the confusion over DUnit, DUnit2 and who was maintaining DUnit? Sourceforge and subversion makes it very difficult to make contributions to projects. I thought about forking DUnit and putting it up on GitHub or Bitbucket,  but my feeling was that would make it even more confusing. Add to that, DUnit was created a long time ago, it's full of IfDefs for CLR, LINUX etc, so it's probably best left alone (I don't have Kylix or Delphi.NET installed). 

DUnitX supports Delphi 2010 or later. If you need support for older versions of Delphi, I'm afraid you will have to stick with DUnit, DUnitX makes use of Generics, Attributes and Anonymous methods. D2010 support has some limitations due to compiler bugs. 

DUnitX - How does it differ from DUnit?

DUnitX is modeled after NUnit, with some ideas borrowed from xUnit as well. The terminology is different to DUnit, so it's worth looking at the differences below :

Feature  DUnit DUnitX
Base Test Class TTestCase None
Test Method Published Published or decorated with [Test]
Fixture Setup Method NA Decorated with [SetupFixture] or constructor*
Test Setup Method Override Setup from base class Decorated with [Setup]
Test TearDown Method Override Teardown from base class Decorated with [TearDown]
Namespaces Through registration parameter (string) Unit Names (periods delimit namespaces).
Data driven Tests NA Decorated with [TestCase(parameters)]
Asserts Check(X) Assert class
Asserts on Containers(IEnumerable) Manual Assert.Contains*, Assert.DoesNotContain*, Assert.IsEmpty*
Asserts using Regular Expressions NA Assert.IsMatch (XE2 or later).
Stack Trace support Jcl Jcl, madExcept 3, madExcept 4, Eurekalog 7 **
Memory Leak Checking FastMM4 FastMM4 (under construction) ** 
IoC Container Use Spring or other Simple IoC container Built in.
Console Logging Built in Built in (quiet or verbose modes).
XML Logging Built in (own format) Built in - Outputs NUnit compatible xml.

* Not available in D2010 due to compiler bugs.
** Extensible,  simple api.

DUnitX is Attribute driven. Any class can be a Test Fixture. The benefit this brings is to isolate internal architecture changes to the test framework from the tests that use the framework.  Logging, stack trace support and memory leak tracking support are extensible and replacable via the built in IoC container and simple interfaces.  The XML Logger for DUnitX outputs NUnit compatible XML, which means the xml can be imported by FinalBuilder and Continua CI (which can display the results nicely).

So what does a DUnitX Test look like?

type
 uses
  DUnitX.TestFramework;
  
type
  [TestFixture('Example','General Example Tests')]
  TExampleFixture = class
  public
    [SetupFixture]
    procedure IamAboutToRunSomeTests;

    [TeardownFixture]
    procedure OKIAmDoneThanks;
    
    [Setup]
    procedure SetupMyTestPlease;
    
    [TearDown]
    procedure TearDownMyTestPlease;
    
    [Test]
    procedure APublicTest;
    
    //Ignored Test will show as ignored in the log.
    [Test]
    [Ignore('Need to rewrite this test')]
    procedure IAmNotReadyToRunYet;
    
    [Test]  
    [TestCase('Case 1','1,2')]
    [TestCase('Case 2','3,4')]
    [TestCase('Case 3','5,6')]
    procedure RunMeMoreThanOnce(param1 : integer; param2 : integer);    
    
    [Test(false)] //Disabled Test. Will not show in the log, will not run
    procedure DontCallMe;
    
  published
    procedure IAmATest;
  end;

Can I convert my DUnit Tests to DUnitX?

DUnitX has limited support for DUnit Tests. Conversion to DUnitX is relatively simple, DUnitX.DUnitCompatibility.pas has a TTestCase class with all the Check(X) methods on it (marked as deprecated, which delegate to the new Assert methods. In the uses clause, replace 

TestFramework

with 

DUnitX.TestFramework,DUnitX.DUnitCompatibility;

and change the registration to 

TDUnitX.RegisterTestFixture(TYourTestClass)

Enabling Stack Trace Support
 

DUnitX has a DUnitX.StackTrace.inc file, uncomment the define for the provider you want to use. If you want to provide your own stack trace provider, then implement IStacktraceProvider and register it with 

TDUnitXIoC.DefaultContainer.RegisterType

Enabling Memory Leak Tracking

This will be similar to the Stack Trace support when fully implemented. 

Where do I get it? Can I contribute?

DUnitX is hosted on GitHub, and we welcome contributions (fork it, make the change and submit a pull request). The project is actively being worked on, with several contributors already. My hope is that someone will help out with MacOS support (we have tried to limit reliance on windows wheree possible).  DUnitX is also the test framework being use for the Delphi Unit Test Project (DUT) started by Nick Hodges. 

Showing 10 Comments

Avatar
Vincent Parrett 11 years ago

We still need support for older versions here as FinalBuilder 7 is written in D2010, all our unit tests have been converted to DUnitX. FinalBuilder 8 (in development) is using XE2. As for the typed pointer issue, I will push a fix for this today. There are only a couple of places impacted and one of them looks wrong anyway. Will test some more before pushing.

I seem to recall the compiler had issues with calling the correct overload for extended values, will have to test again, I wrote the Assert class first, over a year ago.


Avatar
David Heffernan 11 years ago

This seems rather promising indeed. I like the fact that you are embracing the new. Personally I'd encourage you to forget about XE and older and be free from the shackles of their rather crippled generics implementations.

A couple of issues that I discovered:

1. The code is written assuming particular compiler options. I habitually use the typed @ operator option. When I do so in my project, DUnitX fails to build. Since you are writing library code that will be absorbed into all sorts of projects, you are going to need to specify your code's preferred compiler options in your .inc file.

2. I found that Assert.AreEqual failed to compile when passed arguments of type Double. I was building in XE3 and the error message was E2532 Couldn't infer generic type argument from different argument types for method 'AreEqual'. I wrote AreEqual<Double> and made it happy. I note that there is an AreEqual overload for Extended type in there. But not for Double. As someone who does a lot of floating point programming, I'm pretty confident in stating that Extended is mostly pointless. So why pick it out? Anyway, I'm not even sure that the Extended overload is relevant. I suspect that you intend us to write AreEqual<Double>. Is that the case?

I'd be interested in getting involved as a developer for this project. I feel that the moribund state of DUnit is a problem for the Delphi landscape. Your framework looks like it's worth getting behind and supporting with some development effort.


Avatar
Sean B. Durkin 11 years ago

I had the same idea to create an attribute-based unit testing framework for Delphi. I even developed a rough cut, but I did not publish.

Congratulations on this achievement. Someone needed to do it for the Delphi community. It is desperately needed. I have some mixed emotions about this, to the extent that I am disappointed that I was beaten to the punch.

I had a slightly different vision for my framework (to be named SBD Unit Test). It was going to be a paragon of interoperability with other tools - NUnit, FinalBuilder, MSBuild, Jenkins, SmartBear TestComplete.

Let me know if you are interested in contributions in the direction of interoperability with other tools.


Avatar
Vincent Parrett 11 years ago

We don't have a DUnitX action in FinalBuilder yet, however you can just use the Execute Program action to run it. The XML Logger produced NUnit compatible xml, so you can use the Load NUnit XML to import the tests if you are using FinalBuilder Server. I'll look at getting a DUnitX action implemented next week.


Avatar
Roman Kassebaum 11 years ago

How does DUnitX work with FinalBuilder? Under DUnit I'm using TXMLTestListener.


Avatar
Vincent Parrett 11 years ago

@William, I don't have XE installed so haven't gotten around to creating an XE specific project group. You can just take a copy of the 2010 projects and rename and use them. Feel free to fork the project and then create a pull request with the files.


Avatar
Robert Love 11 years ago

Thanks for this, my team has been watching both DUnitX and DUT and are very excited about this.



Avatar
Steven Camilleri 11 years ago

If Embarcadero are really interested in pushing Delphi forward they should encourage more initiatives like this one. How they do that, I don't know, but as a developer, more of this kind of stuff is what I want and what will ultimately keep me!


Avatar
William Meyer 11 years ago

Looks most useful. I do appreciate your continuing efforts, and thank you for them.

That said, I wonder whether I am simply missing something. I downloaded, then tried to build under Delphi XE, using the FinalBuilder project, but it errors out on examples. Looking further, I see no DXE specific groupproj file. Should the FinalBuilder project complete properly, or is that only for later versions of Delphi?


Avatar
jpf 11 years ago

Looks awesome! Can't wait to give it a try. Thanks for the effort!



Comments are closed.