Using Macros with C++ and UnitTest++

163 views Asked by At

I am working on a large C++ project, for safety critical aerospace software, we have about 50 developers working on the project, so of course it is huge, we are using C++ on Red Hat Linux with a little bit of Java and Python, and also small parts of the system are hosted on IBM AIX Unix and Windows.

I recently was hired into this project and found that UnitTest++ was being used to do unit tests. One thing that has me confused is how UnitTest++ is working with macros. It is using a macro to define a derived class and then a call to the macro calls a base class method. It is very unusual, I tried to reproduce the same thing in a small example C++ program but was not able to get it to work. Note the source code for the example program. I am not able to post the specific code in our project due to an NDA.

There should be a way to get this to work, it is working in our unit tests using UnitTest++

// macro2.cpp

#include <iostream>

using namespace std;

class TestBaseClass
{
    public:

    // class constructor
    TestBaseClass() : num1(3), num2(8)
    {
        cout << "Object Created" << endl;
    }

    // class properties
    int num1;
    int num2;

    // class method
    void testMethod()
    {
        cout << "testMethod() called" << endl;
    }

    // class destructor
    ~TestBaseClass()
    {
        cout << "Object Destroyed" << endl;
    }

};


#define TEST_MACRO(TestBaseClass) \
    class TestDerivedClass : public TestBaseClass \
    { \
        public: \
        TestDerivedClass() { num1 = 10; } \ 
    }; \

int main() 
{

    // call macro base class method
    TEST_MACRO(TestBaseClass)
    {
        testMethod();
    }

    return 0;
}
1

There are 1 answers

2
Greg Kramida On

Disclaimer: not 100% sure of how UnitTest++ does it, but Boost unit testing seems to be doing the same thing, and I cannot think of any other this can be done.

The solution is to end the TEST_MACRO with a method signature within the class TestDerivedClass, so that the scope ({ //call to things within TestDerivedClass}) that follows serves as an implementation to that method.

Since you cannot declare a class within a function scope, you'll also need to issue the call to this method via some other structure (i.e. Boost unit testing generates the main method via macros as well)

Here is a working example:

#include <iostream>

using namespace std;

class TestBaseClass
{
public:

    // class constructor
    TestBaseClass() : num1(3), num2(8)
    {
        cout << "Object Created" << endl;
    }

    // class properties
    int num1;
    int num2;

    // class method
    void testMethod()
    {
        cout << "testMethod() called" << endl;
    }

    // class destructor
    ~TestBaseClass()
    {
        cout << "Object Destroyed" << endl;
    }

};


#define TEST_MACRO(TestBaseClass) \
class TestDerivedClass : public TestBaseClass \
{ \
    public: \
    TestDerivedClass() { num1 = 10; } \
    void testMethodInternal(); \
}; \
   \
void TestDerivedClass::testMethodInternal()

// call macro base class method
TEST_MACRO(TestBaseClass)
{
    testMethod();
}

int main()
{
    TestDerivedClass inst;
    inst.testMethodInternal();
    return 0;
}