数据驱动的单元测试与Google Test [英] Data-driven unit tests with google test

查看:160
本文介绍了数据驱动的单元测试与Google Test的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用 googles单元测试框架为嵌入式应用程序编写单元测试。现在我的老板很沮丧,我在测试中硬连接了我测试的数据(即我用来调用被测类的方法的值)。他要求从文件中读取此数据。他的论点是,为以前被遗忘的极端情况添加另一个测试会更容易。我没有单元测试的经验,但是到目前为止,这还不是我的经验。因此,我试图弄清楚什么是最好的方法-即使完全是个好主意。我很快就想到了DDT(数据驱动测试)方法。

I am currently writing unit tests for an embedded application using googles unit test framework. Now my boss got upset that the data I test with (i.e. the values with which I call methods of the class under test) is hard wired in the tests. He requests to have this data read-in from a file. His argument is that it would thus be easier to add another test for a corner case that was previously forgotten. I am not that experienced with unit tests but so far that was not how I did it. So I tried to figure out what would be the best way to do it - even if it is a good idea to do it at all. I quickly came across the DDT (data-driven testing) approach.

google单元测试框架具有一个称为 值参数化测试。这样,我的测试装置便成为模板类,并且可以传递参数。但是,我看到了一些问题:

The google unit test framework has a feature they call "Value-Parameterized Tests". With that my test fixture becomes a template class and I can pass in parameters. However, I see some problems with this:


  • 我目前正在测试每个班级的灯具。但由于每种方法都需要一组不同的参数,因此每种测试方法都需要一个夹具。

  • 如我所见,我只能传递一个参数。由于我的测试需要几个参数(方法的所有参数加上预期的结果),这将要求我传递矢量或映射之类的信息。再次,这种构造和检索听起来像是很多工作。

我原本以为可以像Google测试框架一样成熟更容易。但是,他们编写了

I would have imagined that something as mature as the google test framework to make it easier. However, they write


值参数化的测试很方便[当您想通过各种输入来测试代码时(也就是数据驱动的测试) )。此功能易于滥用,因此在执行此操作时请多加注意!

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:数据驱动陷阱,也警告我(滥用)数据-驱动单元测试。

Additionally there exists this blogpost TotT: Data Driven Traps, also warning me of (abusing) data-driven unit tests.

所以我的问题归结为:


  • 是吗进行数据驱动的单元测试的好主意?

  • 如何使用Google测试框架进行数据驱动的单元测试

我并不是真正地受googletest的束缚,但是基本上可以自由选择我想要的任何框架。

I am not really bound to googletest and basically free to choose any framework I'd like, though.

编辑

我在googletest常见问题解答的FAQ条目中找到了以下语句

I found the following statement in an FAQ entry of the googletest FAQs


总体而言,Google Test还没有对数据驱动测试的良好支持。我们希望能够尽快在这方面进行改进。

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支持它-但也许他们不知道...

GTest has support for it - but maybe they do not know...

使用 testing :: ValuesIn -在此简化示例中:

Use testing::ValuesIn - like in this simplified example:

class SomeTests : public TestWithParam<int>
{
public:

};

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

还有-如何从输入流中获取值的方法:

And - the way how to get values from input stream:

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

要使用比 int更复杂的类型,您需要为其编写一个运算符>>-例如:

To use more complicated types than "int" you need to write an operator >> for it - like:

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> 更专业的迭代器。

Of course - in more complicated cases - consider to use XMl-like (json?) formats and some more specialized iterators than std::istream_iterator<T>.

对于XML-像格式-您可以考虑采用这种方案(这是非常假设的代码-我脑海中没有任何此类库):

For XML - like formats - you might consider such scheme (this is very hypothetical code - I do not have any such library in my mind):

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类型

// etc for any types S1 you want

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

If there is no such C++-type-friendly library on the market (I searched for 2 minutes and did not find) - then maybe something like this:

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

// etc for any node types like S1

这篇关于数据驱动的单元测试与Google Test的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆