I am working on a project in C++. I am writing several unit tests, and I have functions exposed publicly so I can access them in my unit test target executables, but I really don't want them exposed. Is there some way that I can access certain function with unit tests, while hiding them from the public API that's exposed to the client?
Here are three possibilities for you to consider (and there may be more). We'll assume you have:
class A {
private:
int x;
int f();
// ... etc ...
};
Make the private members of A be protected instead. Now, classes inheriting A can access them. So, in your unit test, have something like:
class B : public A {
using A::A;
// ... unit-test-specific code
};
and use B where you would otherwise use A.
Benefit: Original class is not 'polluted' by unit-testing-specific code, and does not need to change when the unit test code changes.
Detriment: Increased visibility of members to actually-inheriting classes. This contradicts the Core Guideline C.133 suggesting we avoid protected members to reduce the potential for mischief and breakage of child classes.
Add to A's definition a declaration of a friend class:
friend class C;
Now, in your unit test, you can access members of A through instances of C. You may want to call the class something more meaningful, e.g. using CRTP:
template <typename T> class unit_test;
class A {
// ... etc ...
friend class unit_test<A>;
// ... etc ...
};
Benefit: No effect on non-unit-test code - its authors do not need to observe any sort of discipline and care.
Detriment: Non-testing code is now "polluted" with a stub for testing code.
Add a macro to your class definition, which usually expands to nothing, but in your unit test code - expands to whatever mechanisms you need to have in class A, or a mechanism/conduit for obtaining them. Example:
#ifndef MYPROJ_A_EXTRA_MEMBERS
#define MYPROJ_A_EXTRA_MEMBERS
#endif
class A {
// ... etc ...
friend class unit_test<A>;
MYPROJ_A_EXTRA_MEMBERS
// ... etc ...
};
and in your unit test, you would have something like:
#define MYPROJ_A_EXTRA_MEMBERS \
float y; \
int g(int);
before including public API
if you need members y and g().
Benefit: No effect on non-unit-test code - its authors do not need to observe any sort of discipline and care. After preprocessing, and in user code, the non-testing code is not "polluted" with anything.
Detriment: Macros are ugly; they make it more difficult to debug; and they don't play well with modules.