Unit Testing in Delphi by using DUnit

Unit Test Introduction
Unit testing defines that each unit test sends a specific input to a method and verifies that the method returns the expected value, or takes the expected action. Unit tests prove that the code you are testing does in fact do what you expect it to do.

For more about Unit Testing please visit http://www.extremeprogramming.org/rules/unittests.html

The Value of Unit Tests
One of the most valuable benefits of unit tests is that they give you confidence that your code works as you expect it to work. Unit tests give you the confidence to do long-term development because with unit tests in place, you know that your foundation code is dependable. Unit tests give you the confidence to refactor your code to make it cleaner and more efficient. Unit tests also save you time because unit tests help prevent regressions from being introduced and released. Once a bug is found, you can write a unit test for it, you can fix the bug, and the bug can never make it to production again because the unit tests will catch it in the future. Another advantage is that unit tests provide excellent implicit documentation because they show exactly how the code is designed to be used. 

DUnit 
DUnit is an open-source unit test framework based on the JUnit test framework. The DUnit framework allows you to build and execute tests against Delphi Win32 applications. Delphi 2006 or later integrates an open-source testing framework DUnit. It allows you to build and run automated test cases for your Delphi applications. These frameworks simplify the process of building tests for classes and methods in your application. Using unit testing in combination with refactoring can improve your application stability. Testing a standard set of tests every time a small change is made throughout the code makes it more likely that you will catch any problems early in the development cycle. The testing framework is based on the JUnit test framework and share much of the same functionality. 

How to install
DUnit gets installed automatically by the Delphi 2006 or later installer. You can find many DUnit resources in the \source\DUnit directory, under your primary installation directory. These resources include documentation and test examples. When using DUnit, at a minimum you usually include at least one test case and one or more test fixtures. Test cases typically include one or more assertion statements to verify the functionality of the class being tested. DUnit is licensed under the Mozilla Public License 1.0 (MPL) Open source and free.

Architecture of DUnit test framework

Test Projects 
A test project encapsulates one or more test cases and is represented by a node in the IDE Project Manager. You can create a test project before creating test cases. Once you have a test project that is associated with a code project, you can add test cases to the test project. Delphi 2006 or later provides a Test Project Wizard to help you build a test project.

Test Cases 
Every class that you want to test must have a corresponding test class. You define a test case as a class in order to instantiate test objects, which makes the tests easier to work with. You implement each test as a method that corresponds to one of the methods in your application. More than one test can be included in a test case. The ability to group and combine tests into test cases and test cases into test projects is what sets a test case apart from simple forms of testing, such as using print statements or evaluating debugger expressions. Each test case and test project is reusable and re-runable, and can be automated through the use of shell scripts or console commands. Generally, you should create your tests in a separate project from the source file project. That way, you do not have to go through the process of removing your tests from your production application. Delphi 2006 or later provides a Test Case Wizard to help you build test cases. You can add test cases directly into the same project as your source file, however, doing so increases the size of your project. You can also conditionally compile your test cases out of production code by using IFDEF statements around the test case code.

Test Fixtures 
The term test fixture refers to the combination of multiple test cases, which test logically related functionality. You define test fixtures in your test case. Typically, you will instantiate your objects, initialize variables, set up database connection, and perform maintenance tasks in the SetUp and TearDown sections. As long as your tests all act upon the same objects, you can include a number of tests in any given test fixture.

SetUp and TearDown
One often needs to do some common preparation before running a group of tests, and some tidying up afterwards. For example, when testing a class, you might want to create an instance of that class, run some checks on it, and finally free it. If you have a lot of tests to make, you'll end up with repetitive code in each test method. DUnit provides support for these situations through the TTestCase virtual methods SetUp and TearDown, which are called, respectively, before and after each test method is executed. 

Using of DUnit for Unit Testing in Delphi
The Delphi 2006 or later integration of DUnit allows you to test Delphi  applications. Each testing framework provides its own set of methods for testing conditions. The methods represent common assertions. You can also create your own custom assertions. You will be able to use the provided methods to test a large number of conditions. To do unit testing we need to create a sample Delphi project whose functionality will be being tested and a DUnit test project which will provide GUI and functionality to do testing of Sample Delphi Application code. 

Lets create a sample Delphi application
So before creating DUnit test project and test cases, lets create sample Delphi project or class which will be used for testing. Here I created a project and added a unit Calcunit having TCalc class

//a sample class whole functionality will be used for unit testing//
unit CalcUnit;

interface

type

{ TCalc }

  TCalc = class
  public
    function Add(x, y: Integer): Integer;
    function Substract(x, y: Integer): Integer;
    function Multiply(x, y: Integer): Integer;
    function Division(x, y: Integer): Integer;
  end;

implementation

{ TCalc }

function TCalc.Add(x, y: Integer): Integer;
begin
  Result := x + y;
end;

function TCalc.Substract(X, Y: Integer): Integer;
begin
  Result := x - y;
end;

function TCalc.Multiply(x, y: Integer): Integer;
begin
  Result := x * y;
end;

function TCalc.Division(x, y: Integer): Integer;
begin
  Result := x div y;
end;

end.

Steps to create DUnit test project 
Now check the steps to create DUNIT test project or test cases for testing TCalc class properties and functions. This topic includes information about: 
Building DUnit Tests. 
DUnit Functions. 
DUnit Test Runners. 

Building DUnit Tests 
Every DUnit test implements a class of type TTestCase. The following sample Delphi Win32 program defines two functions that perform simple addition and subtraction: 

Building Tests Cases using Delphi projects is the simplest way
The structure of a unit test is largely dependent on the functionality of the class and method you are testing. The Unit Test Wizards can help you by providing a template of the test project, setup and teardown methods, and basic tests. You will need to add the specific test logic to test a particular method. The following procedures describe how to build your test projects and test cases. Follow these procedures in order. The test project must be built prior to the test cases.

To build a test project 
1. Choose File ->New ->Other. 
2. Open the “Unit Test” folder. 
3. Double-click the Test Project gallery item. 

This starts the Test Project Wizard.

4. Enter the project name or accept the default name. 
5. Enter the location or accept the default location. 
6. Select the personality or accept the default. By default, the personality is set to Delphi for Delphi Projects. 
7. If you do not want the test project added to your project group, uncheck the Add to Project Group check box.


8. Click Next. 
9. Choose the GUI or Console test runner, then click Finish. Here I chose GUI as it is easy to use.

The Test Project Wizard adds the necessary references to your project. Project file will be look as follow

program CalcTest;
{$IFDEF CONSOLE_TESTRUNNER}
{$APPTYPE CONSOLE}
{$ENDIF}
uses
  DUnitTestRunner,
  TestCalcUnit in 'TestCalcUnit.pas', // will be added later after testcase create//
  CalcUnit in '..\testproj\CalcUnit.pas'; // will be added later after testcase create//

{$R *.RES}

begin
  DUnitTestRunner.RunRegisteredTests;
end.

Steps to build a test case 
1. Click the Code tab for the file containing the classes you want to test. This makes the file active in the Code Editor. 
2. Choose File -> New -> Other. 
3. Open the “Unit Test” folder. 
4. Double-click the Test Case gallery item. 

This starts the Test Case Wizard.

5. Choose a source file from the Source File drop down list. 
All source files in your project are listed. Here I selected CalcUnit.pas having class TCalc for testing.


6. Select the classes and methods you want to build tests for, by checking or unchecking the check boxes next to the class and method names, in the Available classes and methods list. You can deselect individual methods in the list. The wizard will build test templates for the checked methods only. 
7. Click Next. Check the File Name and fill appropriate details or accept the defaults.


8. Click Finish. The wizard creates a test case file and creates a name for the file by prefixing the name of the active code file with the word Test. 

Initialize and Finalize objects or variable
Now to write a test case code for initialize and finalize objects or variable.
1. Add code to the SetUp and TearDown methods, if needed. 
2. Add asserts to the test methods if needed.

The added unit shows the test case skeleton file that you need to modify to test the TCalc class functions;

unit TestCalcUnit;
interface
uses
  TestFramework, CalcUnit;
type
  // Test methods for class TCalc
  TestTCalc = class(TTestCase)
  strict private
    FCalc: TCalc;
  public
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestAdd;
    procedure TestSubstract;
    procedure TestMultiply;
    procedure TestDivision;
  end;
implementation
procedure TestTCalc.SetUp;
begin
  FCalc := TCalc.Create;
end;
procedure TestTCalc.TearDown;
begin
  FCalc.Free;
  FCalc := nil;
end;
procedure TestTCalc.TestAdd;
var
  ReturnValue: Integer;
  y: Integer;
  x: Integer;
begin
  // TODO: Setup method call parameters
  ReturnValue := FCalc.Add(x, y);
  // TODO: Validate method results
end;
procedure TestTCalc.TestSubstract;
var
  ReturnValue: Integer;
  y: Integer;
  x: Integer;
begin
  // TODO: Setup method call parameters
  ReturnValue := FCalc.Substract(x, y);
  // TODO: Validate method results
end;
procedure TestTCalc.TestMultiply;
var
  ReturnValue: Integer;
  y: Integer;
  x: Integer;
begin
  // TODO: Setup method call parameters
  ReturnValue := FCalc.Multiply(x, y);
  // TODO: Validate method results
end;
procedure TestTCalc.TestDivision;
var
  ReturnValue: Integer;
  y: Integer;
  x: Integer;
begin
  // TODO: Setup method call parameters
  ReturnValue := FCalc.Division(x, y);
  // TODO: Validate method results
end;
initialization
  // Register any test cases with the test runner
  RegisterTest(TestTCalc.Suite);
end.

DUnit Procedures and Functions 
DUnit provides a number of functions that you can use in your tests. 

Function
Description
Check
Checks to see if a condition was met.
CheckEquals
Checks to see that two items are equal.
CheckNotEquals
Checks to see if items are not equal.
CheckNotNull
Checks to see that an item is not null.
CheckNull
Checks to see that an item is null.
CheckSame
Checks to see that two items have the same value.
EqualsErrorMessage
Checks to see that an error message emitted by the application matches a specified error message.
Fail
Checks that a routine fails.
FailEquals
Checks to see that a failure equals a specified failure condition.
FailNotEquals
Checks to see that a failure condition does not equal a specified failure condition.
FailNotSame
Checks to see that two failure conditions are not the same.
NotEqualsErrorMessage
Checks to see that two error messages are not the same.
NotSameErrorMessage
Checks that one error message does not match a specified error message.

For more information on the syntax and usage of these and other DUnit functions, please see the DUnit help files in \source\dunit\doc. 

Using Check
Check is a DUnit function which takes in two parameters; the first is the logical operation and the second is the error message or information to report if something did go wrong.

For Example 
Check( x = 5, 'X should be 5');5');
Check( y <> 0, 'Y should not be 0');1');

DUnit Test Runners
A test runner allows you to run your tests without impacting your application. The DUnit test project you create is your test runner. You can indicate the Text TestRunner to output test results to the console. The GUI test runner displays your results interactively in a GUI window right in the IDE. The results are color-coded to highlight which tests succeeded and which failed. The GUI test runner is very useful when actively developing unit tests or the code you are testing. The GUI test runner displays a green bar over a test that completes successfully, a red bar over a test that fails, and a yellow bar over a test that is skipped. The DUnit console/text test runner is useful when you need to run completed code and tests from automated build scripts

To run the test case in the GUI Test Runner 
1. Click the Code tab for the file containing the classes you want to run. 
2. Choose Run -> Run (F9). The GUI Test Runner starts up immediately on execution of your application. The list of tests appears in the left pane of the GUI Test Runner. 


3. Select one or more tests. 
4. Click the Run button. The test results appear in the Test Results window. Any test highlighted with a green bar passed successfully. Any test highlighted in red failed. Any test highlighted in yellow was skipped. 
5. Review the test results. 
6. Fix the bugs and rerun the tests.


Video: Delphi Unit Tests, by Mike Rozlog

Comments

  1. Great post, thx.

    Does anyone know at what version of Delphi did the shipped DUnit start using the DUnitTestRunner unit in place of GUITestRunner?

    I'm trying to build some tests that can be compiled with all Delphis back to XE and I know DUnitTestRunner doesn't work with XE but does with XE4 -- I don't have the intermediate Delphis to test with. If need to use conditional compilation and make the switch at the correct version.

    Thanks in advance folks.

    ReplyDelete
  2. Software testing training in Mumbai
    nice blog
    Software testing classes in Mumbai

    ReplyDelete
  3. Fantastic blog, really nice blog, and useful to all. Informative and knowledgeable content. Thanks for sharing this blog with us. Keep sharing more stuff like this.
    Data Science Online Training in Hyderabad

    ReplyDelete

  4. Unit testing is the software testing technique where a group of software program components or modules are tested individually. This technique effectively helps in validating the accuracy of a section of code by considering stubs, mock objects, drivers, and unit testing frameworks.

    ReplyDelete
  5. IT's very informative blog and useful article thank you for sharing with us , keep posting learn more about Product engineering services | Product engineering solutions.

    ReplyDelete
  6. This was definitely one of my favorite blogs. Every post published did impress me.
    business analytics course in hyderabad

    ReplyDelete
  7. thank you for sharing best opinion following us. i at the back of your say and all you share in the back of us is uptodate and quite informative, i'd in imitation of to bookmark the page suitably i can come right here once more to retrieve you, as you have got finished a terrifi process.! Product Key For Windows 7 Ultimate

    ReplyDelete
  8. I in plan of fact respect the fine of subjects you proclaim here. thanks for sharing us a on your liking opinion that is certainly obliging. good hours of day!! Microsoft Office 2010 Cracker

    ReplyDelete
  9. You have amazing writing skills and you display them in every article. Keep it going!
    Choose our Online Course Visit cyber security Training

    ReplyDelete
  10. I would love to see this blog /post its because its content was very nice.
    Unhackme Crack

    Notepad Crack

    ReplyDelete
  11. First of all, I would like to thank you for sharing this great piece of content.
    Math is one of the most important subjects for any student in any class. Mathematics is a subject that includes topics such as knowledge of numbers, shapes, spaces, volume, distance etc. It is seen that some students find math interesting, on the other hand some students find math as difficult. This is because most of the students take Maths Online Tuition classes from the starting of their session so that they can score good grades.
    The Ultimate Guide to Stars and the Milky Way

    ReplyDelete
  12. Best blog keep Posting check out this website for idx website development Dpi Web

    ReplyDelete

Post a Comment

Popular posts from this blog

ShellExecute in Delphi

How to send Email in Delphi?

Drawing Shapes in Delphi