Here is a typical C++ code:
foo.hpp
#pragma once
class Foo {
public:
void f();
void g();
...
};
foo.cpp
#include "foo.hpp"
namespace {
const int kUpperX = 111;
const int kAlternativeX = 222;
bool match(int x) {
return x < kUpperX || x == kAlternativeX;
}
} // namespace
void Foo::f() {
...
if (match(x)) return;
...
It looks like a decent idiomatic C++ code - a class, a helper function match
which is used by the methods of Foo
, some constants for that helper function.
And then I want to write tests.
It would be perfectly logical to write a separate unit test for match
, because it's quite non-trivial.
But it resides in an anonymous namespace.
Of course I can write a test which would call Foo::f()
. However it won't be a good test if Foo
is heavy and complicated, such test won't isolate the testee from other unrelated factors.
So I have to move match
and everything else out of the anonymous namespace.
Question: what's the point of putting functions and constants into the anonymous namespace, if it makes them unusable in tests?
3 Answers 3
If you want to unit-test the private implementation-details, you do the same sort of dodge for unnamed namespaces as for private (or protected) class-members:
Break in and party.
While for classes you abuse friend
, for unnamed namespaces you abuse the #include
-mechanism, which doesn't even force you to change the code.
Now that your test-code (or better only something to expose everything) is in the same TU, there's no problem.
A word of caution: If you test the implementation-details, your test will break if those change. Be really sure to only test those implementation-details which will leak anyway, or accept that your test is unusually ephemeral.
The function in your example looks quite complex, and it may be better to move it to the header, for the purpose of unit testing.
what's the point of putting functions and constants into the anonymous namespace, if it makes them unusable in tests?
To make them isolated from rest of the world. And it is not only functions and constants that you can put in the anonymous namespace - it is also for types.
However, if it makes your unit tests very complex, then you are doing it wrong. In such case the function doesn't belong there. Then it is time for a little refactoring to make the testing simpler.
So, in anonymous namespace should go only very simple functions, sometimes constants and types (including typedefs) used in that translation unit.
It would be perfectly logical to write a separate unit test for match, because it's quite non-trivial.
The code you showed for match
is a pretty trivial 1-liner without any tricky edge cases, or is that like a simplified example? Anyway, I'll assume it's simplified...
Question: what's the point of putting functions and constants into the anonymous namespace, if it makes them unusable in tests?
This question is what wanted to make me jump in here since Deduplicator already showed a perfectly good way to break in and get access through #include
trickery. But the wording here makes it sounds like testing every single internal implementation detail of everything is some kind of universal end goal, when it's far from it.
The goal of even unit testing isn't always to test every little granular internal micro-unit of functionality. The same question applies to static file-scope functions in C. You can even make the question harder to answer by asking why developers use pimpls
in C++ which would require both friendship
and #include
trickery to white box, trading easy testability of implementation details for improved compilation times, e.g.
From a kind of pragmatic perspective, it might sound gross but match
may not be correctly implemented with some edge cases that cause it to trip up. However, if the sole outer class, Foo
, that has access to match
cannot possibly use it in a way that encounters those edge cases, then it's rather irrelevant to the correctness of Foo
that match
has these edge cases that will never be encountered unless Foo
changes, at which point the tests of Foo
will fail and we'll know immediately.
A more obsessive mindset eager to test every single internal implementation detail (perhaps a mission-critical software, e.g.) might want to break in and party, but a lot of people don't necessarily think that's the best idea, as it would create the most brittle tests imaginable. YMMV. But I just wanted to address the wording of this question which makes it sound like this kind of uber-fine-grained-internal-detail-level testability should be an end goal, when even the most rigorous unit testing mindset might relax a bit here and avoid x-raying the internals of every class.
So why do people define functions in anonymous namespaces in C++ or as file-scope static functions with internal linkage in C, hidden from the outside world? And that's mainly it: to hide them from the outside world. That has a number of effects from reducing compile times to reducing complexity (what cannot be accessed elsewhere cannot cause problems elsewhere) and so forth. Probably testability of private/internal implementation details isn't the number one thing on people's minds when they do it over, say, reducing build times and hiding unnecessary complexity from the outside world.
-
I wish I could upvote this ten times. As a tangent related to mission critical, high assurance software, you are much more concerned with the correctness of details. This idiomatic-style for C++ is not suited for that. I would not use features of the language like anonymous namespaces or proxy-like patterns. I would control my boundary coarsely with [supported] user-space headers and [unsupported] developer space headers.David– David2018年06月11日 13:05:55 +00:00Commented Jun 11, 2018 at 13:05
foo.cpp
, not the header! OP seems to understand quite well that you shouldn't put anon namespaces in a header.friend
keyword for that purpose is not recommended.Combine that with your assumption that if a restriction for a method leads to a situation where you cannot test it directly any more, that would imply private methods were not useful.