Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Testing Protected or Private Members

When testing a large class, you may find yourself wanting to test protected or private members of the class. The best approach is to test those members by testing the public members of the class. If using the public members of a class requires considerable setup in order to force execution down a particular path that exercises the protected or private member in question, then you may wish to refactor the code to enhance testability.

The most expedient technique for protected members is to raise their visibility through derivation. Suppose we have a base class B with a protected member p that we wish to test:

class B
{
// ... other stuff in B
protected:
    bool p();
};

We can derive a class D in the test code from the class B in the production code that raises the visibility of p:

class D : public B
{
// ... other stuff needed to build a D from a B
public:
    using B::p;
};

Now we can write a test for D::p.

While this certainly seems expedient, it's annoying to write these derived classes simply for the purposes of hoisting members into public visibility. It also just feels dirty. We're taking implementation details that are supposed to be hidden from consumers of the class and we're exposing them. If we are not diligent and watchful, this class D in the test project that was only intended for testing may find itself showing up in the production code.

Maybe the problem isn't one of visibility but that we simply aren't listening closely enough to the code in the first place. As Herb Sutter shows us in Uses and Abuses of Access Rights, the "Liar", the "Pickpocket", the "Cheat" and the "Language Lawyer" can all find ways to subvert the access protections afforded to a class.

When we are tempted to test non-public methods of a class, it's because we feel that there is sufficient complexity in these non-public methods to warrant testing them. What if that complexity is trying to tell us something? If our class is so complex, isn't it possible that it's violating the Single Responsibility Principle? Maybe the class is trying to encompass several responsibilities and should be decomposed into two or more classes, each with a single responsibility. We could perform the Extract Class refactoring to create two classes with appropriate public interfaces and then write tests against those new public interfaces.

Another choice is to refactor the original class using the "pimpl idiom", elevate the visibility to public of all the methods on the implementation class and write tests against the implementation class. This has the same downsides as the derive-and-elevate approach and we're still ignoring the whispers of the code.

When your code is hard to test, your code is telling you something. Listen to the code!


PrevUpHomeNext