Monday, December 30, 2013

I have been a big fan of using unit testing frameworks. I use both DUnit and DUnitX for my Delphi tests.

I am right now contributing to DUnitX as I see it as the future framework of choice for Delphi Developers.

I just wanted to talk in public about some of work I have going on around DUnitX. My goal is simple to get feedback from the Delphi community.

IDE Expert

It is really easy to setup a test project and test fixtures with DUnitX, but I thought it could be easier.

So I created a new Delphi Open Tools Expert that does the following:

File | New | Other | Delphi Projects | DUnitX Project

Creates a new DPR/DPROJ

DPR Source is modeled after the DUnitX example unit tests.

Base Project Search Path set to $(DUnitX)

Optionally creates a Test Unit

File | New | Other | Delphi Files | DUnitx Unit

Creates new Delphi unit

Adds DUnitX.TestFramework to uses

Creates a new class with correct attributes, you get to specify class name

Optionally creates Setup and TearDown methods

Optionally creates Sample Test Methods.

Registers the TestFixture in the initialization section.

Basically it's not much, but it provides a framework to reduce your time to get to writing actual test code. I am nearly done with this code, I wrote most of it during the Christmas Break. Hopefully in the next week I can finish this. It's going to take some time, as I have to build a machine with Delphi 2010 through XE5 on it to test this functionality as I only have XE and XE5 installed right now.

The method Test2 above shows up as two different tests, the first time it's called with 1 and and second time it's called with 3 and 4.

I recently made a change to underlying structure of the code. First I created a new record called TestCaseInfo followed by two new abstract attribute classes

///
/// Internal Structure used for those implementing CustomTestCase or
/// CustomTestCaseSource descendants.
///
TestCaseInfo = record
///
/// Name of the Test Case
///
Name : string;
///
/// Values that will be passed to the method being tested.
///
Values : TValueArray;
end;
TestCaseInfoArray = array of TestCaseInfo;
///
/// Base class for all Test Case Attributes.
///
///
/// Class is abstract and should never be, used to annotate a class as a
/// attribute. Instead use a descendant, that implements the GetCaseInfo
/// method.
///
CustomTestCaseAttribute = class abstract(TCustomAttribute)
protected
function GetCaseInfo : TestCaseInfo; virtual; abstract;
public
property CaseInfo : TestCaseInfo read GetCaseInfo;
end;
///
/// Base class for all Test Case Source Attributes.
///
///
///
/// Class is abstract and should never be, used to annotate a class as a
/// attribute. Instead use a descendant, that implements the
/// GetCaseInfoArray method.
///
///
/// Note: If a method is annotated with a decendant of
/// TestCaseSourceAttribute and returns an empty TestCaseInfoArray, then
/// no test will be shown for the method.
///
///
CustomTestCaseSourceAttribute = class abstract(TCustomAttribute)
protected
function GetCaseInfoArray : TestCaseInfoArray; virtual; abstract;
public
property CaseInfoArray : TestCaseInfoArray read GetCaseInfoArray;
end;

With these two classes, I changed TestCaseAttribute to descend from CustomTestCaseAttribute.
Then I changed the architecture to create a Test based on the TestCaseInfo record structure, that is obtained by either the CaseInfo or the CaseInfoArray properties of the abstract classes.

This little change provides for some really nice functionality, for example I have working sample that uses FireDAC to provide the
values to my tests method

This attribute is not in the DUnitX.TestFramework.pas to avoiding creating dependencies on those that don't use this functionality. This needs quite a bit of work before it's polished enough for general use, but it's what I am working on next after the expert is submitted as a pull request.

Note: Since FireDac changed it's naming, I believe it might be XE4 or XE5 specific.

Repeat Attribute

DUnitX defines a RepeatAttribute that is currently not implemented. I made an attempt at implementing it, and I don't like it. If anyone has better idea, I would be happy to entertain it.

Otherwise, I have some small improvements I think I will make and will submit it again.

Future Plans

Things I want see in a Unit Testing framework is vast, I not sure what I will start on next but here are some areas I am considering with no preference on order. Note: this is not a road map as some may never be done (at least by me)