The C Googletest is fairly well documented as to how to write templated tests for standard types. What I need, however, is write tests where the template is an enum
and the implementations are specific values of that enum
. I can't figure out how to make this work with the tools available (or whether it's even possible).
Copying the examples, I've been trying something along the lines of:
enum Dinosaur { Trex = 0, Stegosaur = 1, Triceratops = 2 };
using MyDinosaurs = ::testing::Types<
Dinosaur::Trex,
Dinosaur::Stegosaur,
Dinosaur::Triceratops>; // This line does not compile, since Dinosaur::Trex etc aren't actually types
template <Dinosaur Dinosaur_T>
class DinosaurTest : public ::testing::Test
{
private:
DinosaurFactory<Dinosaur_T> m_dinosaurFactory;
};
TYPED_TEST_SUITE(DinosaurTest, MyDinosaurs);
TYPED_TEST_P(DinosaurTest, DinosaurEnumTest)
{
ASSERT_NE(nullptr, m_dinosaurFactory.Create());
}
REGISTER_TYPED_TEST_SUITE_P(DinosaurTest, DinosaurEnumTest);
INSTANTIATE_TYPED_TEST_SUITE_P(MyDinosaurTestSuite, DinosaurTest, MyDinosaurs); // This line then also does not compile, since 'MyDinosaurs' isn't a valid list of types
How can I make a test in this fashion work for enums?
CodePudding user response:
You can use std::integral_constant
to actually provide type instead of value:
using MyDinosaurs = ::testing::Types<
std::integral_constant<decltype(Dinosaur::Trex),Dinosaur::Trex>,
std::integral_constant<decltype(Dinosaur::Trex), Dinosaur::Stegosaur>,
std::integral_constant<decltype(Dinosaur::Trex), Dinosaur::Triceratops>>;
You can call ::value
on your std::integral_constant
to actually get the enum value
so, modify your fixture to:
template <typename T>
class DinosaurTest : public ::testing::Test
{
public:
DinosaurFactory<T::value> m_dinosaurFactory; // T::value is your enum type
}
With these modifications, you are set. You can check complete example based on your problem here: https://godbolt.org/z/97eszrMsK
Note: I'm not sure if there is another way, I haven't found it.
You can also use this approach instead of std::integral_constant
:
template <Dinosaur N>
struct EnumValue{
static const Dinosaur value = N;
};
using MyDinosaurs = ::testing::Types<
EnumValue<Dinosaur::Trex>,
EnumValue<Dinosaur::Stegosaur>,
EnumValue<Dinosaur::Triceratops>>;
The rest is the same as above.
CodePudding user response:
Are you sure you want to have a type as the test parameter and not a value?
It seems to me that you need to test the DinosaurFactory
given different Dinosaur
types from your enum. So perhaps your DinosaurFactory
should not be a template but it should just take the type as a parameter?
If that's the case, you can use a Parameterized Test instead of Typed tests as below:
enum class Dinosaur { Trex = 0, Stegosaur = 1, Triceratops = 2 };
class CDinosaur {
public:
CDinosaur(Dinosaur type) : m_type(type) {}
Dinosaur m_type;
};
class DinosaurFactory {
public:
CDinosaur* Create(Dinosaur type) { return new CDinosaur(type); }
};
class DinosaurTest : public testing::TestWithParam<Dinosaur> {
public:
DinosaurFactory m_dinosaurFactory;
};
// This will create multiple tests.
TEST_P(DinosaurTest, DinosaurEnumTest) {
auto type = GetParam();
auto actual = m_dinosaurFactory.Create(type);
ASSERT_NE(nullptr, actual);
if (actual != nullptr) {
delete actual;
}
}
INSTANTIATE_TEST_SUITE_P(DinosaurTestWithFactory, DinosaurTest,
testing::Values(Dinosaur::Trex, Dinosaur::Stegosaur,
Dinosaur::Triceratops));
Live example: https://godbolt.org/z/MdjbrTfEP
Side notes:
- Use
enum class
instead ofenum
. - Don't forget to delete the pointer resulting from
m_dinosaurFactory.Create
or use aunique_ptr
.