DUnit Testing in C++ Builder

By | December 30, 2016


So while building a new OTA project to provide C++ Builder with Ctrl+Shift+Up/Down code navigation and code completion functionality I needed to write some C++ DUnit tests. Now I know that DUnit is no longer being developed and that I should use DUnitX but since I know the framework and am already learning C++ 11 and OTA in C++ builder I didn't want to add another thing to learn at this time however I will sometime in the future.

So why am I writing about this? Well the documentation I found on http://docwiki.embarcadero.com/RADStudio/Seattle/en/DUnit_Overview doesn't work in Berlin and I suspect that it hasn't worked for C++ Builder since the introduction of the new RTTI. It compiles BUT it throws an RTTI exception when run.

So why don't I use the DUnit wizards from the IDE? Well the project one works but the test case version raises an blank exception. I've raised this as a bug (https://quality.embarcadero.com/browse/RSP-16631). Please vote for this if you want it fixed.

DUnit Project

So the DUnit Project wizard in the IDE will create a DUnit project for you as shown below.

// DUnit Project File.
//   Entry point of C++ project using DUnit framework.

#include <System.hpp>
#pragma hdrstop
#include <tchar.h>
#include <vcl.h>
#include <GUITestRunner.hpp>

#pragma comment(lib,"CodeSiteLoggingPkg.lib")
#pragma link "CodeSiteLogging"

  catch (Exception &exception)
  catch (...)
   throw Exception("");
 catch (Exception &exception)
  return 0;

The only other things I've added are some compiler conditionals to include CodeSite so that I could put messages in the constructors and destructors of my collaboration object to ensure they were being fired correctly.

DUnit TestCase

Below is a test case similar to that found on the docwiki above.


To solve the problem with the RTTI exception I had to add __declspec(delphirtti) to the class declaration. Once this was added the tests ran however there are some peculiarities. It runs tests in the public and published scopes not just published.

The other mistake I made which took a few hours for the penny to drop was I had spelt Setup wrong. It should be spelt SetUp.

#ifndef CPPBuilderToolsParserTestH
#define CPPBuilderToolsParserTestH

#include "CBTBaseTestCase.h"
#include <TestFramework.hpp>
#include "CPPBuilderToolsParser.h"

class __declspec(delphirtti) TCBTParserTests : public TCBTBaseTestCase {
    std::unique_ptr<TStringList> FCode;
    void __fastcall SetUp();
    void __fastcall TearDown();
    virtual __fastcall TCBTParserTests(String strName) : TCBTBaseTestCase(strName) {};
    void __fastcall TestParser();



Below is the implementation of the above class which should be straight forward.

#pragma hdrstop
#include "CPPBuilderToolsParserTest.h"
#include "CPPBuilderToolsFunctions.h"
#pragma package(smart_init)

void __fastcall TCBTParserTests::SetUp() {
  FCode = std::unique_ptr<TStringList>{ new TStringList() };
  String strFileName = ExtractFilePath(ParamStr(0)) + "..\\..\\TestFile.cpp";

void __fastcall TCBTParserTests::TearDown() {

void __fastcall TCBTParserTests::TestParser() {
  std::unique_ptr<ICBTParser> P { new TCBTParser(L"MyUnit.cpp") };
  ICBTUnit* U = P->Parse(FCode.get());
  CheckEquals(1, U->ClassCount);

static void registerTests()
  _di_ITestSuite iSuite;
  TTestSuite* testSuite = new TTestSuite("CBT Parser Tests");
  if (testSuite->GetInterface(iSuite)) {
  } else {
    delete testSuite;
#pragma startup registerTests 33

The only other difference that is noticable is with the static funtion declared at the end to register the test case suites. This and the following #pragma code are there to workaround C++ not having the Object Pascal equivalent to an initialization section.

After Thoughts

I've written this blog post mostly to remind me later on how I solved the issues but hopefullly it will be useful to others wanting to use DUnit in C++ Builder.