Sometimes, we need to provide a specific constructor solely for test usage. How can we force such constructor is solely used in test code, nowhere else. I just wonder if this is achievable in c++11/14. e.g.,
class A {
public:
A() = default; // used only in test code
}
class A_Test : public ::testing::Test {
private:
A a; // it is ok.
};
class A_Production {
private:
A a; // compiler error
}
I could imagine to use friend
decorator and put the specific constructor in protected
to limit the access. but there are other existing friends in legacy code too. Is it possible to make a custom specifier like protected in c++1x?
any ideas?
You could use the Passkey Idiom:
Instead of a direct friendship, you limit the access to A
from A_Test
through the indirection provided by ConstructorKey
, which A
uses in its interface where it wants the friends of ConstructorKey
to access.
class A {
class ConstructorKey {
friend class A_Test;
private:
ConstructorKey() {};
ConstructorKey(ConstructorKey const&) = default;
};
public:
// Whoever can provide a key has access:
explicit A(ConstructorKey); // Used only in test code
};
class A_Test : public ::testing::Test {
private:
A a {ConstructorKey{}}; // OK
};
class A_Production {
private:
A a {ConstructorKey{}}; // Compiler error
};
I can think of several ways to do that.
Make the constructor protected
, with only the test subclass using it.
Add a forward declaration to some dummy class, class TestClassThatShouldNotBeUsedInProductionCode;
, then declare a constructor that takes a reference to this class as a parameter:
A::A( /* other constructor arguments */,
const TestClassThatShouldNotBeUsedInProductionCode &)
This constructor can simply ignore this parameter altogether. Your test module can define this dummy, empty class: class TestClassThatShouldNotBeUsedInProductionCode {};
, and be able to construct your A
class using it. Only your test module would be able to use this constructor, then, and its name makes it pretty clear what the purpose of this is. There isn't really any way to define certain translation units as "real" code versus "test" code, in C++, you just want to implement a clear policy that would be hard to violate accidentally.
Some variations are possible, such as using an inner class instead of forward-declaring a standalone class. The inner class could only be instantiated only by the test code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With