I'm trying to write a value-parameterized test, where the test values are only created once the test classes have been instantiated, i.e. the test values are stored in a non-static variable. This means I cannot do what I normally do, where the container is static:
INSTANTIATE_TEST_CASE_P(SomeCriteria, SomeTest,
ValuesIn(SomeClass::staticContainerWithTestINputs) );
Here is an MVCE example at the point I am stuck:
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace testing;
// This is not a test class, so I can't modify `myInt` to be static just so
// that I can write tests.
struct CustomClass
{
int myInt = 0;
};
class Fixture : public ::testing::Test {
protected:
CustomClass myCustomCls;
virtual void SetUp() override
{
// This variable needs to be used in the parameterized test.
myCustomCls.myInt = 42;
}
};
class ValueParamTest : public Fixture, public WithParamInterface<int> {
public:
// The container holding the values to be tested.
const std::vector<int> validInputs {
1, 24, myCustomCls.myInt
};
protected:
virtual void SetUp()
{
Fixture::Fixture::SetUp();
mTestInput = GetParam();
}
int mTestInput;
};
TEST_P(ValueParamTest, ValidInputs)
{
EXPECT_TRUE(mTestInput < 100);
}
// COMPILER ERROR HERE
INSTANTIATE_TEST_CASE_P(ValidInputValues, ValueParamTest,
ValuesIn(ValueParamTest::validInputs) );
The compiler error:
59: error: invalid use of non-static data member ‘ValueParamTest::validInputs’
ValuesIn(ValueParamTest::validInputs) );
^
There is no instance of that ValueParamTest
class, so I cannot access its instance data members or member functions.
Anyone could give a hint how this could be done in GTest?
How to Write Value-Parameterized Tests. To write value-parameterized tests, first you should define a fixture class. It must be derived from both testing::Test and testing::WithParamInterface<T> (the latter is a pure interface), where T is the type of your parameter values.
TEST_P() is useful when you want to write tests with a parameter. Instead of writing multiple tests with different values of the parameter, you can write one test using TEST_P() which uses GetParam() and can be instantiated using INSTANTIATE_TEST_SUITE_P() .
Parameterized tests are a good way to define and run multiple test cases, where the only difference between them is the data. They can validate code behavior for a variety of values, including border cases. Parameterizing tests can increase code coverage and provide confidence that the code is working as expected.
Seemingly Googletest's macro repertoire does not run to your requirement, but by The Fundamental Theorem of Software Engineering, you can do the like of this:-
main.cpp
#include <gtest/gtest.h>
#include <functional>
#include <memory>
using namespace testing;
struct CustomClass
{
int myInt = 0;
};
class Fixture : public ::testing::Test {
protected:
static std::shared_ptr<CustomClass> & getSpecimen() {
static std::shared_ptr<CustomClass> specimen;
if (!specimen) {
specimen.reset(new CustomClass{42});
}
return specimen;
}
void TearDown() override
{
getSpecimen().reset();
}
};
class ValueParamTest :
public Fixture, public WithParamInterface<std::function<int()>> {
public:
static std::vector<std::function<int()>> validInputs;
protected:
void SetUp() override {
mTestInput = GetParam()();
}
void TearDown() override {
Fixture::TearDown();
}
int mTestInput;
};
std::vector<std::function<int()>> ValueParamTest::validInputs{
[]() { return 1; },
[]() { return 24; },
[]() { return ValueParamTest::getSpecimen()->myInt; }
};
TEST_P(ValueParamTest, ValidInputs)
{
std::cout << "mTestInput = " << mTestInput << std::endl;
EXPECT_TRUE(mTestInput < 100);
}
INSTANTIATE_TEST_CASE_P(ValidInputValues, ValueParamTest,
ValuesIn(ValueParamTest::validInputs) );
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Which builds and runs like:
g++ -Wall -std=c++14 -o gtestrun main.cpp -lgtest -pthread && ./gtestrun
[==========] Running 3 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 3 tests from ValidInputValues/ValueParamTest
[ RUN ] ValidInputValues/ValueParamTest.ValidInputs/0
mTestInput = 1
[ OK ] ValidInputValues/ValueParamTest.ValidInputs/0 (0 ms)
[ RUN ] ValidInputValues/ValueParamTest.ValidInputs/1
mTestInput = 24
[ OK ] ValidInputValues/ValueParamTest.ValidInputs/1 (1 ms)
[ RUN ] ValidInputValues/ValueParamTest.ValidInputs/2
mTestInput = 42
[ OK ] ValidInputValues/ValueParamTest.ValidInputs/2 (0 ms)
[----------] 3 tests from ValidInputValues/ValueParamTest (1 ms total)
[----------] Global test environment tear-down
[==========] 3 tests from 1 test case ran. (1 ms total)
[ PASSED ] 3 tests.
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