c++ - 使用 google test 进行数据驱动的单元测试

标签 c++ unit-testing testing googletest data-driven-tests

我目前正在使用 googles unit test framework 为嵌入式应用程序编写单元测试.现在我的老板对我测试的数据(即我调用被测类的方法的值)在测试中硬连接感到不安。他请求从文件中读入该数据。他的论点是,这样可以更容易地为以前被遗忘的极端情况添加另一个测试。我对单元测试没有那么丰富的经验,但到目前为止我还不是这样做的。所以我试图弄清楚什么是最好的方法——即使这样做是个好主意。我很快发现了 DDT(数据驱动测试)方法。

Google 单元测试框架有一个功能,他们称之为“Value-Parameterized Tests”。这样我的测试夹具就变成了一个模板类,我可以传入参数。但是,我看到了一些问题:

  • 目前,我对每个待测类都有一个夹具。但是我需要为每个被测方法准备一个夹具,因为每个方法都需要一组不同的参数。这将需要大量额外工作。
  • 据我所知,我只能传入一个参数。因为我需要几个用于我的测试(我的方法的所有参数加上预期结果)这将需要我传递 vector 或 map 之类的东西。同样,这种构建和检索听起来需要大量工作。

我本以为像 google 测试框架这样成熟的东西会让它变得更容易。然而,他们写

value-parameterized tests come handy [when] you want to test your code over various inputs (a.k.a. data-driven testing). This feature is easy to abuse, so please exercise your good sense when doing it!

此外还有这篇博文 TotT: Data Driven Traps ,还警告我注意(滥用)数据驱动的单元测试。

所以我的问题归结为:

  • 进行数据驱动的单元测试是个好主意吗?
  • 如何使用谷歌测试框架进行数据驱动的单元测试

不过,我并不是真的受制于 googletest,基本上可以自由选择任何我喜欢的框架。

编辑

我在 googletest FAQs 的一个 FAQ 条目中发现了以下语句

Google Test doesn't yet have good support for [...] data-driven tests in general. We hope to be able to make improvements in this area soon.

最佳答案

GTest 支持它 - 但也许他们不知道......

使用 testing::ValuesIn - 就像这个简化的例子:

class SomeTests : public TestWithParam<int>
{
public:

};

TEST_P(SomeTests, shouldBePositive)
{
    ASSERT_GT(GetParam(), 0);
}

以及 - 如何从输入流中获取值的方式:

std::ifstream inputValuesFromFile("input.txt");
INSTANTIATE_TEST_CASE_P(FromFileStream,
                        SomeTests,
                        ValuesIn(std::istream_iterator<int>(inputValuesFromFile), 
                                 std::istream_iterator<int>()));

要使用比“int”更复杂的类型,你需要为它写一个运算符>>——比如:

struct A
{
    int a;
    std::vector<int> b;
}
std::istream& operator >> (std::istream& is, A& out)
{
     std::size_t bSize;
     if ((is >> A.a) && (is >> bSize))
     {
         out.b.reserve(bSize);
         while (bSize-- > 0)
         {
             int b;
             if (!(is >> b))
                break;
             out.b.push_back(b);   
         }
     }
     return is;
}

当然 - 在更复杂的情况下 - 考虑使用类似 XMl(json?)的格式和一些比 std::istream_iterator<T> 更专业的迭代器.


对于类似 XML 的格式,您可能会考虑这样的方案(这是非常假设的代码 - 我的脑海中没有任何这样的库):

SomeLib::File xmlData("input.xml");

class S1BasedTests : public TestWithParam<S1>
{};

TEST_P(S1BasedTests , shouldXxxx)
{
    const S1& s1 = GetParam();
    ...
}
auto s1Entities = file.filterBy<S1>("S1");
INSTANTIATE_TEST_CASE_P(S1,
                        S1BasedTests,
                        ValuesIn(s1Entities.begin(), s1Entities .end()));

//等你想要的任何类型的 S1


如果市场上没有这样的 C++ 类型友好的库(我搜索了 2 分钟,没有找到)——那么可能是这样的:

SomeLib::File xmlFile("input.xml");

struct S1BasedTests : public TestWithParam<SomeLib::Node*>
{
   struct S1 // xml=<S1 a="1" b="2"/>
   {
       int a;
       int b;
   };
   S1 readNode()
   {
        S1 s1{};
        s1.a = GetParam()->getNode("a").getValue<int>();
        s1.b = GetParam()->getNode("b").getValue<float>();
        return s1;
   }
};

TEST_P(S1BasedTests , shouldXxxx)
{
    const S1& s1 = readNode();
    ...
}
INSTANTIATE_TEST_CASE_P(S1,
                        S1BasedTests ,
                        ValuesIn(xmlFile.getNode("S1").getChildren()));
                        // xml=<S1s> <S1.../> <S1.../> </S1>

//等任何节点类型,如 S1

关于c++ - 使用 google test 进行数据驱动的单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40286104/

相关文章:

c++ - 是否将指针转换为 const 指针并转换回未定义的原始类型?

c++ - 对头文件稍作修改是否需要重新编译第三方库

python - 在同一个python函数中模拟两个具有不同返回值的redis hget

javascript - 测试 Jest 单元测试并总是得到未定义的结果

javascript - Jasmine 测试 postMessage API

php - Behat 外部文件中的步骤定义

javascript - 在 mocha 中断言函数失败 "assert"导致超时而不是失败

c++ - winsock 选择函数出现堆栈溢出异常 (0xC00000FD)

c++ - gSoap,c++,如何在客户端应用程序中传递 soapStub 声明的参数

python - Django 自动为任意管理表单生成 POST 数据字典