Unit testing c++. How to test private members?

Answering this question touches many other topics. Beside any religiosity in CleanCode, TDD and others:

There are several ways to access private members. In any case you have to overrule the tested code! This is possible on both levels of parsing C++ (preprocessor and language itself):

Define all to public

By using the preprocessor you are able to break encapsulation.

#define private public
#define protected public
#define class struct

The disadvantage is, that the class of the delivered code is not the same as in the test! The C++ Standard in chapter 9.2.13 says:

The order of allocation of non-static data members with different access control is unspecified.

This means, that the compiler has the right to reorder the member variables and virtual functions for the test. You may struggle, that this won't harm your classes if no buffer overflow happens, but it means, that you won't test the same code as you deliver. It means, that if you access members of an object, that was initialized by code, compiled with private not defined to public, the offset of your member may differ!

Friends

This method needs to change the tested class for befriending it with the test class or the test function. Some testing frameworks like gtest (FRIEND_TEST(..);) have special functionality to support this way of accessing private things.

class X
{
private:
    friend class Test_X;
};

It opens the class only for the test and does not open up the world, but you have to modify the code that gets delivered. In my opinion this is a bad thing, because a test should never change the tested code. As a further disadvantage it gives other classes of the delivered code the possibility to intrude your class by naming themselves like a test class (this would also harm the ODR rule of the C++ Standard).

Declaring the private things protected and derive from the class for tests

Not a very elegant way, very intrusive, but works also:

class X
{
protected:
    int myPrivate;
};

class Test_X: public X
{
    // Now you can access the myPrivate member.
};

Any other way with macros

Works, but has the same disadvantages on standard conformity like the first way. e.g.:

class X
{
#ifndef UNITTEST
private:
#endif
};

I think that the last both ways are no alternatives to the first two ways, because they have no advantages over the first ones, but are more intrusive on the tested code. The first way is very risky, so you may use the befriending approach.


Some words on the never-test-private-things-discussion. One of the upsides of unit testing at all is, that you will reach very early the point, where you have to improve the design of your code. This is also sometimes one of the downsides of unit testing. It makes object orientation sometimes more complicated, than it has to be. Especially if you follow the rule to design classes in the same way the real world objects are.

Then you have to change the code sometimes into something ugly, because the unit testing approach forces you to do so. Working on complex frameworks, that are used to control physical processes, is one example. There you want to map the code on the physical process, because often parts of the process are already very complex. The dependency list on that processes gets sometimes very long. This is one possible moment, where testing private members is getting nice. You have to trade-off with the advantages and disadvantages of each approach.

Classes are getting sometimes complex! Then you have to decide to split them or to take them as they are. Sometimes the second decision makes more sense. In the end it is always a question of which goals you want to achieve (e.g. perfect design, quick incorporation times, low development costs...).


My Opinion

My decision process for accessing private members looks like this:

  1. Do you need to test private members themselves? (Often this reduces the total number of tests needed)
  2. If yes, do you see any design advantage to refactor the class?
  3. If no, befriend the test in your class (use this because of the missing alternatives).

I don't like the befriending approach, because it changes the tested code, but the risk to test something, that may not be the same as delivered (as possible with the first approach), will not justify the cleaner code.

BTW: Testing only the public interface is also a fluent matter, because in my experience it changes as often as the private implementation does. So you have no advantage to reduce the test on public members.


Typically, one only tests the public interface as discussed in the question's comments.

There are times however when it is helpful to test private or protected methods. For example, the implementation may have some non-trivial complexities that are hidden from users and that can be tested more precisely with access to non-public members. Often it's better to figure out a way to remove that complexity or figure out how to expose the relevant portions publicly, but not always.

One way to allow unit tests access to non-public members is via the friend construct.


I haven't found a golden solution myself, but you can use friend to test private members, if you know how the testing framework names it's methods. I use the following to test private members with Google test. While this works quite well, note that it's a hack, and I don't use it in production code.

In the header of the code I want to test (stylesheet.h), I have:

#ifndef TEST_FRIENDS
#define TEST_FRIENDS
#endif

class Stylesheet {
TEST_FRIENDS;
public:
    // ...
private:
    // ...
};

and in the test I have:

#include <gtest/gtest.h>

#define TEST_FRIENDS \
    friend class StylesheetTest_ParseSingleClause_Test; \
    friend class StylesheetTest_ParseMultipleClauses_Test;

#include "stylesheet.h"

TEST(StylesheetTest, ParseSingleClause) {
    // can use private members of class Stylesheet here.
}

You always add a new line to TEST_FRIENDS if you add a new test that accesses private members. The benefits of this technique are that it is fairly unobstrusive in the tested code, as you only add a few #defines, which have no effect when not testing. The downside is that it is a bit verbose in the tests.

Now one word as to why you would want to do this. Ideally of course, you have small classes with well-defined responsibilities, and the classes have easily testable interfaces. However, in practice that's not always easy. If you are writing a library, what is private and public is dictated by what you want the consumer of the library to be able to use (your public API), and not by what's in need of testing or not. You can have invariants that are very unlikely to change, and need to be tested, but are of no interest to the consumer of your API. Then, black-box-testing of the API is not enough. Also if you encounter bugs and write additional tests to prevent regressions, it can be neccessary to test private stuff.