— anonymous
For good reasons, class designers usually keep implementation details out of the public interface. In object-oriented programming, this is called “encapsulation” and is generally considered a good thing. However, when unit testing such a class, it’s sometimes desirable to access private members of a class to verify that a class indeed works correctly, not just on the “surface” (i. e. the public interface). As an example, take this contrived C++ class that we want to develop our unit tests against:
1 2 3 4 5 6 7 8 9 |
class Client { public: void publicMethod(); private: void privateMethod(); std::array<double, 100> values; }; |
If we attempt to access ‘privateMethod’ or the ‘values’ array from our tests, we’re out of luck, since they’re both declared private.
There are several known solutions to work around this problem:
- Simply don’t use the ‘private’ and ‘protected’ access modifiers; declare all members ‘public’. While this is common practice in the Python community, it’s shunned by the C++ community.
- When the unit test build runs, let the preprocessor substitute all occurrences of ‘private’ (or ‘protected’) with ‘public’ by specifying the substitution as a command-line argument to the compiler (i. e. -Dprivate=public). While this is quite pragmatic and doesn’t require any code changes, some folks refuse to accept such behind-the-scenes preprocessor trickery.
- Instead of directly using ‘private’ and ‘protected’ access modifiers in your class definition, use your own preprocessor symbols like ‘PRIVATE’ and ‘PROTECTED’. During a regular build, these symbols are replaced via the preprocessor with ‘private’ and ‘protected’, respectively; during a unit test build, they both are expanded to ‘public’. While this approach is more transparent than the previous approach, it’s not at all pleasant to look at and there’s no syntax-highlighting support by editors/IDEs.
- Access the inaccessible members via a trusted entity, an attorney. In the remainder of this post, I’ll explain this approach.
Generally speaking, one risk of making many private details easily accessible during unit test builds is that unit test developers are seduced into making their tests too dependent on low-level implementation details, which makes future refactorings much harder. The attorney pattern also gives you low-level access but in a much more controlled fashion; it forces you to be explicit about what you want to access:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
class ClientAttorney { public: ClientAttorney(Client& client) : client_(client) { } void privateMethod() { client_.privateMethod(); } auto& values() { return client_.values; } private: Client& client_; }; TEST(attorney, simple_test) { Client client; ClientAttorney attorney(client); attorney.privateMethod(); attorney.values()[0] = 12.34; } |
ClientAttorney is basically a limited, forwarding proxy around an existing Client instance that makes part of Client’s implementation details publicly available. For this to work, ClientAttorney obviously needs to be declared a ‘friend’ in Client’s class definition:
1 2 3 4 5 6 7 8 9 10 11 12 |
class ClientAttorney; // forward declaration. class Client { public: void publicMethod(); private: friend ClientAttorney; // friend declaration. void privateMethod(); std::array<double, 100> values; }; |
While some folks complain that this requires too much typing, proponents emphasize that this exactly the strong point of the attorney pattern: in order to be able to do something shady you have to invest a little effort, which automatically reduces the amount of shadiness that you introduce into your unit tests.
Personally, I like this explicit approach, but I never liked all the boilerplate. It’s not just tedious to type and maintain: If the signature of a Client method changes subtly (say a parameter changes from ‘int’ to ‘double’), inconsistencies can remain dormant for quite some time until suddenly problems arise. So in my tests I use this templated variant of the attorney pattern:
1 2 3 4 5 6 7 8 9 10 |
// attorney.h template<class TClient> class Attorney : public TClient { public: Attorney(TClient& client) : client_(client) { } private: TClient& client_; }; |
Then, in my unit testing project, all I need to do is this:
1 2 3 4 5 6 7 8 9 10 11 |
#include "Client.h" #include "utils/attorney.h" class ClientAttorney : public Attorney<Client> { public: using Attorney<Client>::Attorney; // inherit Attorney constructor. using Client::privateMethod; // selectively export member method. using Client::values; // selectively export member object. }; |
By employing subclassing and ‘using’ declarations, I can redeclare existing private base class (Client) members as public without having to worry about future type or signature changes. This solution still forces developers to be explicit but avoids most of the tediousness and is at the same time less error-prone.