Unit testing of private methods

C++Unit TestingPrivate Methods

C++ Problem Overview


I am in the process of writing some unit tests. In particular I want to test some private methods.

So far the I have come up with using.

#define private public

But I am not happy with this as it will destroy all encapsulation from the point of view of the unit test.

What methods do you use to unit-test private methods.

C++ Solutions


Solution 1 - C++

Rather than the nasty #define hack you mention in the question, a cleaner mechanism is to make the test a friend of the class under test. This allows the test code (and just the test code) access to the privates, whilst protecting them from everything else.

However, it is preferable to test through the public interface. If your class X has a lot of code in the private member functions then it might be worth extracting a new class Y which is used by the implementation of class X. This new class Y can then be tested through its public interface, without exposing its use to the clients of class X.

Solution 2 - C++

If you're using Google Test, you can use FRIEND_TEST to easily declare your test fixture as a friend to the class under test.

And you know, if testing private functions were unequivocally bad like some of the other answers were saying, then it probably wouldn't be built into Google Test.

You can read more about when testing private functions is good or bad in this answer.

Solution 3 - C++

If the methods are complex enough to warrant testing in isolation, then refactor them into their own class(es) and test via their public interface(s). Then use them privately in the original class.

Solution 4 - C++

Make the test class as the friend of the original class. This friend declaration will be inside the #define UNIT_TEST flag.

class To_test_class {
   #ifdef UNIT_TEST
     friend test_class;
   #endif
}

Now for your unit test you will compile the code with flag -DUNIT_TEST. This way you will be able to test the private function.

Now your unit test code will not be pushed into production environment, as UNIT_TEST flag will be false. Hence the code is still secure.

Also you will not need any special library for unit testing.

Solution 5 - C++

I know this is an older question, but it seems that nobody has shared the relatively good method that I prefer, so here it goes:

Change the method you wish to test from private to protected. For other classes, the method is still going to be private, but now you can derive a "testing" class from your base class that exposes the private functionality you want tested.

Here's a minimal example:

class BASE_CLASS {
  protected:
    int your_method(int a, int b);
};

class TEST_CLASS : public BASE_CLASS {
  public:
    int your_method(int a, int b) {
      return BASE_CLASS::your_method(a, b);
    }
}

Of course you will have to update your unit tests to run your tests on the derived class instead of the base class, but after that, any change made to the base class will be automatically reflected in the "testing" class.

Solution 6 - C++

After many hours this is what I decided to be the best solution for ones that want to test their private functions. This is combination of answers by Max DeLiso and Miloš.

If you are using boost::unit-test then there's an easy and elegant solution.

  1. Use protected instead of private in your classes

     /* MyClass.hpp */
    
     class MyClass {
    
     protected:
         int test() {
             return 1;
         }
     };
    
  2. Create a fixture:

     /* TestMyClass.cpp */
    
     class F : public MyClass {};
    
    
     BOOST_FIXTURE_TEST_SUITE(SomeTests, F)
    
     // use any protected methods inside your tests
     BOOST_AUTO_TEST_CASE(init_test)
     {
         BOOST_CHECK_EQUAL( test(), 1 );
     }
     BOOST_AUTO_TEST_SUITE_END()
    

This way you can freely use any of the MyClass functions without #define private public or adding friends to you class!

Solution 7 - C++

The define hack is a horrible idea. Arbitrarily re-writing your code with the preprocessor when you go to compile it is never wise.

Now as several people have mentioned already, it's debatable whether you should be testing private methods at all. But this doesn't cover the case where you've intentionally hidden constructors to restrict instantiaton to certain scopes, or a few other more esoteric cases.

Also, you can't friend a namespace and "friendship" is not inherited in C++ so depending on your unit testing framework you could be in trouble. Luckily, if you're using Boost.Test, there's in elegant solution to this issue in the form of Fixtures.

http://www.boost.org/doc/libs/1_52_0/libs/test/doc/html/utf/user-guide/fixture/per-test-case.html

You can friend the fixture and have it instantiate all of the instances that you use in your unit testing functions, declaring them as static to the fixture and with module scope. If you're using a namespace don't worry, you can just declare your fixture within the namespace and your test cases outside of the namespace, and then use the scope resolution operator to get to the static members.

The BOOST_FIXTURE_TEST_CASE macro will take care of instantiating and tearing down your fixture for you.

Solution 8 - C++

I don't think unit test cases would be required for private methods.

If a method is private it can used only within that class. If you have tested all the public methods using this private method then there is no need to test this separately since it was used only in those many ways.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMumblesView Question on Stackoverflow
Solution 1 - C++Anthony WilliamsView Answer on Stackoverflow
Solution 2 - C++jlstreckerView Answer on Stackoverflow
Solution 3 - C++Mike SeymourView Answer on Stackoverflow
Solution 4 - C++Manoj RView Answer on Stackoverflow
Solution 5 - C++MilošView Answer on Stackoverflow
Solution 6 - C++PariView Answer on Stackoverflow
Solution 7 - C++Max DeLisoView Answer on Stackoverflow
Solution 8 - C++aehView Answer on Stackoverflow