I am aware that there is a popular notion that implementation details do not warrant testing and/or that the implementation should just be made public. For the sake of this question, please assume that there is merit to both testing and to minimising the API.
How should one go about testing an internal free function?
// Example for C
static MyType do_something_internal(OtherType * X);
// Or (roughly) equivalently
namespace { MyType do_something_internal(OtherType * X); }
The option we currently take is to expose the call, but in a detail namespace:
// Preserve the friendly function name and internal linkage
static MyType do_something_internal(OtherType * X)
extern MyType detail_do_something_internal(OtherType *X)
{ return do_something_internal(OtherType *X); }
// C++ version preserving the external linkage of the original
namespace detail {MyType do_something_internal(OtherType * X);}
We could instead expose a single object containing references to the internal functions:
struct exposed_for_test {
auto detail_do_something_internal = do_something_internal;
auto detail_other = other;
} // Similar in C, but somewhat less convenient to write out
We could wrap the testing interface in preprocessor macros with varying degrees of care:
#ifndef TESTING_BUILD
#define LINKAGE extern
#else
#define LINKAGE static
#endif
LINKAGE MyType do_something_internal(OtherType * X)
// or:
#ifdef TESTING_BUILD
static MyType do_something_internal(OtherType * X);
extern MyType detail_do_something_internal(OtherType * X)
{ return MyType do_something_internal(OtherType * X); }
#endif
At present I am leaning towards the last option. Any non-test code that calls the exposed interface will fail to link in the release build. However, this seems to unavoidably double compile time, and it feels a little uncomfortable to test different object files to those released. Perhaps it would be better to leave the testing interface in place and rely on link time optimisation to strip it out.
I am also considering writing the test code inline with the release code to access static functions directly. This clutters up the "real code" with "test code" though, and is probably a contentious solution.
All of the above options seem pretty crude however, so I'd like to ask the community - do you have any better ideas, or do you favour one of the above? Thank you.
Aucun commentaire:
Enregistrer un commentaire