10/25/2019

How to unit test a private function in C++

Introduction
Automated software tests are becoming more and more popular. Thank for the idea of Test Driven Development (TDD) unit tests are used more often and often.
To implement unit tests first we have to define what is a unit? In object oriented environment usually a class is encountered as a unit. So that in case of unit testing we are testing the behavior of a class.
One way of thinking here is that only the public interfaces needs to be tested, since the private ones are only used by the public functions of the class, so if someone if using are class from outside, only uses the public interfaces and don’t have knowledge about the private ones. This is also true.
On the other hand one important KPI is the code coverage and to reach 100% code coverage the easiest way is to test the private functions separately. In some cases the private functions are really complex and it is difficult to test all they corner cases through the public functions.
So there is a need for testing private functions. But it is not so trivial to do it, since private functions are not callable from outside of the class.
I collected some possible solutions for testing them. The solutions are dedicated to C++, but most of them can be also used with other object oriented programming languages.

Possible solutions



  1. Friend class


In C++ a friend class of a class can also see its private attributes and functions. So make your test fixture class friend to the tested class and you can unit test its private functions.
However it has the disadvantage that you have to modify the code of your tested class (by the line adding the friend class). So this solution is not too elegant.


#include


class UnitTestClass;


class ToBeTested
{
private:
    int Calculate() { return 0; }
    
friend UnitTestClass;
};


class UnitTestClass
{
public:
    void RunTest()
    {
        ToBeTested object_under_test;
        if (object_under_test.Calculate() == 0)
        {
            std::cout << "Test passed" << std::endl;;
        }
        else
        {
            std::cout << "Test failed" << std::endl;;
        }
    }
};


int main()
{
  UnitTestClass unit_tester;
  unit_tester.RunTest();
  return 0;
}


  1. Define private public


In c++ preprocessor directives gives you a lot of chances to cheat. You can just put such a code into your test file:

#define private public
#include
#undef private

Ugly, right? But it works...

  1. Make it protected and inherit


You can change your private functions to protected, so that they have the same behavior until you are not inheriting from your class. And now you can inherit your test fixture class from you class under test, so that you can reach all its protected functions.
The dark side of this solution that you are changing your production code only for testing purposes and you are making it less safe in case of inheritance.


#include


class ToBeTested
{
protected:
    int Calculate() { return 0; }   
    
};


class UnitTestClass : ToBeTested
{
public:
    void RunTest()
    {
        if (Calculate() == 0)
        {
            std::cout << "Test passed" << std::endl;;
         }
        else
        {
            std::cout << "Test failed" << std::endl;;
        }
    }
};


int main()
{
  UnitTestClass unit_tester;
  unit_tester.RunTest();
  return 0;
}


  1. Move it to a separate class


The solution which in letting your code done in the most object oriented and in the most clean way is to move the function to be tested into a new class. So if you have for example a complex Calculate private function in your class, which should be unit tested, just move it to a new Calculator class. Or to a class which is a collection of helper functions. And add a private member of your new class to your old class. In this way your code will be more testable, reusable and thanks to technologies like dependency injection you can exchange your algorithm in a more elegant way in the future and you can also easily mock it to unit test the other parts of your class. This is the solution which I prefer, since in this way you will have smaller classes, with clear, well-defined responsibility.

#include


class UnitTestClass;


class Calculator
{
public:
int GetResult() { return 0; }
};


class ToBeTested
{
private:
    Calculator calculator;
    
};


class UnitTestClass
{
public:
    void RunTest()
    {
        Calculator calculator_under_test;
        if (calculator_under_test.GetResult() == 0)
        {
            std::cout << "Test passed" << std::endl;;
        }
        else
        {
            std::cout << "Test failed" << std::endl;;
        }
    }
};


int main()
{
  UnitTestClass unit_tester;
  unit_tester.RunTest();
  return 0;
}

Summary
There are several other hacks which makes you able to test private functions, like playing with preprocessor directives, or use FRIEND_TEST option of GTEST, but at the end of the day these are all just versions of the solutions which I previously mentioned.

The best and most preferred solution is absolutely language independent: make your architectecture clean. This is always a good way to create nice software.

No comments:

Post a comment

Software development in automotive sector

Introduction The automotive business changed a lot during the last decades. Earlier a car was built up from poor hardware, without any s...