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:
- Do you need to test private members themselves? (Often this reduces the total number of tests needed)
- If yes, do you see any design advantage to refactor the class?
- 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.