为 Google 测试夹具指定构造函数参数
Posted
技术标签:
【中文标题】为 Google 测试夹具指定构造函数参数【英文标题】:Specify constructor arguments for a Google test Fixture 【发布时间】:2016-11-07 12:31:12 【问题描述】:通过 Google 测试,我想指定一个用于不同测试用例的测试夹具。
夹具应分配和释放类TheClass
及其数据管理类TheClassData
的对象,其中数据管理类需要数据文件的名称。
对于不同的测试,文件名应该不同。
我定义了以下 Fixture:
class TheClassTest : public ::testing::Test
protected:
TheClassTest(std::string filename) : datafile(filename)
virtual ~TheClassTest()
virtual void SetUp()
data = new TheClassData(datafile);
tc = new TheClass(data);
virtual void TearDown()
delete tc;
delete data;
std::string datafile;
TheClassData* data;
TheClass* tc;
;
现在,不同的测试应该使用具有不同文件名的夹具。 将其想象为设置测试环境。
问题:如何从测试中指定文件名,即如何调用夹具的非默认构造函数?
我发现了诸如 ::testing::TestWithParam<T>
和 TEST_P
之类的东西,这并没有帮助,因为我不想用不同的值运行一个测试,而是用一个夹具运行不同的测试。
【问题讨论】:
所以你想自己运行那个夹具? google test 默认测试运行器无法实例化带参数的fixture。 我想使用夹具运行测试(可能是TEST_F
)。所以答案是,这不可能吗?谢谢。
我认为TestWithParam<T>
和TEST_P
正是您所需要的。查找Advanced Docs 如何在实践中使用它们。您始终可以在测试用例中实例化被测实例(我假设它是TheClass
)。
【参考方案1】:
根据另一位用户的建议,您无法实现您想要的
通过使用非默认构造函数实例化夹具。然而,
还有其他方法。只需重载SetUp
函数并
在测试中显式调用该版本:
class TheClassTest : public ::testing::Test
protected:
TheClassTest()
virtual ~TheClassTest()
void SetUp(const std::string &filename)
data = new TheClassData(filename);
tc = new TheClass(data);
virtual void TearDown()
delete tc;
delete data;
TheClassData* data;
TheClass* tc;
;
现在在测试中只需使用这个重载来设置文件名:
TEST_F(TheClassTest, MyTestCaseName)
SetUp("my_filename_for_this_test_case");
...
无参数TearDown
会自动清理
测试完成。
【讨论】:
太棒了。非常感谢! SetUp 方法仍将被 gtest 调用,导致两次调用 SetUp ...因此在这种情况下存在内存泄漏,因为 TearDown 仅删除最后的分配。我会将 SetUp 重命名为其他名称,以便 gtest 不会调用它。 对不起,我错了。由于您的Setup
带有一个参数,因此 gtest 不会调用它。我会将 SetUp
重命名为其他名称,因为它可能与 gtest 调用的 SetUp()
混淆。【参考方案2】:
使用当前类作为您的灯具的基类:
class TheClassTestBase : public ::testing::Test
protected:
TheClassTestBase(std::string filename) : datafile(filename)
...
;
对于每个特定的文件名 - 使用派生的夹具:
class TheClassTestForFooTxt : public TheClassTestBase
protected:
TheClassTestForFooTxt() : TheClassTestBase ("foo.txt")
;
但是,对于每组参数,这都是额外的步骤 - 因此您可以尝试使用模板或宏来轻松完成它。喜欢:
template <typename ClassTestTag>
struct ClassTestParams
static std::string filename;
;
template<typename ClassTestTag>
class TheClassTest : public TheClassTestBase
protected:
TheClassTest() : TheClassTestBase (ClassTestParams<ClassTestTag>::filename)
;
然后 - 对于每组参数 - 这样做:
class FooTxtTag ;
template <> std::string ClassTestParams<FooTxtTag>::value = "foo.txt";
using TheClassTestForFooTxt = TheClassTest<FooTxtTag>;
TEST_F(TheClassTestForFooTxt, xxxx)
但是 - 在您的具体情况下 - 我也会尝试 GoogleTest:type-parameterized-tests。
【讨论】:
谢谢。我认为这对于我的问题规模来说有点过分了。 文档链接已损坏【参考方案3】:解决这个问题的另一种好方法是扩展您的夹具,并在扩展类中提供一个新的默认构造函数,该构造函数使用您需要的参数调用旧构造函数。例如:
struct MySpecializedTestFixture : public GenericTestFixture
MySpecializedTestFixture() : GenericTestFixture("a thing", "another thing")
;
TEST_F(MySpecializedTestFixture, FancyTest)
// Use the thing environment and make some assertions.
【讨论】:
【参考方案4】:如果您按照建议的here 重载SetUp
方法,并且要确保记住使用重载的SetUp
,则可以在TearDown
方法中使用断言。
class my_fixture : public ::testing::Test
protected:
bool SETUP_HIT_FLAG = false;
void SetUp(double parameter)
...
SETUP_HIT_FLAG = true;
void TearDown() override
assert(SETUP_HIT_FLAG && "You forgot to call SetUp with your parameter!");
;
【讨论】:
【参考方案5】:对于这种特殊情况,我觉得完全摆脱测试夹具要容易得多。 SetUp
函数可以替换为使用所需文件名实例化类的辅助函数。这允许使用TEST
而不是TEST_P
或TEST_F
。现在每个测试用例都是一个独立的测试,它使用辅助函数或直接在测试用例的主体中创建自己的测试类实例。
例如:
using namespace testing;
TEST(FooClassTest, testCase1)
FooClass fooInstance("File_name_for_testCase1.txt");
/* The test case body*/
delete fooInstance;
【讨论】:
OP 询问有关使用测试夹具的问题。这个例子没有展示如何重用datafile
、data
和tc
。 delete fooInstance
怎么了?以上是关于为 Google 测试夹具指定构造函数参数的主要内容,如果未能解决你的问题,请参考以下文章