I have an interface for which I have three implementations. I am using the TYPED_TEST from google test so that I can use the same set of tests for all implementations. I have the following Fixture.
template <typename T>
class GenericTester : public ::testing::Test {
protected:
T test_class;
};
I added the implementation types below.
using TestTypes = ::testing::Types<ImplementationOne, ImplementationTwo>
TYPED_TEST_SUITE(GenericDiffTester, DiffTypes);
So far, everything works fine, but now I have added another implementation. The difference between the last implementation is that its constructor requires taking a std::string
as an argument, whereas the first two can be default constructed.
Now when I add this third interface, it does not compile.
using TestTypes = ::testing::Types<ImplementationOne, ImplementationTwo, ImplementationThree>
TYPED_TEST_SUITE(GenericDiffTester, DiffTypes);
Obviously, the problem is that the fixture requires test_class
to be default constructible, which does not apply to ImplementationThree
.
How can I initialize the templated member variable of a class depending on the provided type T? I want to default construct test_class if T is of type ImplementationOne or ImplementationTwo. Otherwise, I want to construct it as ImplementationThree with a string.
Is there a way to do it directly with Gtest without a hacky solution?
CodePudding user response:
The easiest way is to derive from your non-default constructible class. That derived class could be default constructible:
class TestableImplementationThree : public ImplementationThree
{
public:
TestableImplementationThree() :
ImplementationThree("dummy")
{}
};
And:
using TestTypes = ::testing::Types<
ImplementationOne,
ImplementationTwo,
TestableImplementationThree>;
If you like to test ImplementationThree with different constructor argument - then just create and test as many testable-classes as needed.
if you do insist on testing exactly ImplementationThree
- then wrap all classes with some kind of holders. For ImplementationThree
specialize its "holder" to construct it differently.
template <typename T>
struct Holder
{
T tested_object;
};
template <>
struct Holder<ImplementationThree>
{
ImplementationThree tested_object{"dummy"};
};
template <typename T>
class GenericTester : public ::testing::Test,
protected Holder<T>
{
};