测试套件属性的 Gtest RecordProperty()

Gtest RecordProperty() for testsuite attribute

使用Google测试框架进行单元测试,是否可以配置输出XML文件属性?我知道 'test case' 属性是可能的。是否可以配置 XML 文件的顶级属性('testsuite''testsuites')?

这是我从文档中得到的:允许在测试生命周期之外调用 RecordProperty()。如果在测试之外但在测试用例的 SetUpTestCase()TearDownTestCase() 方法之间调用它,它将归因于测试用例的 XML 元素。如果它在所有测试用例之外调用(例如在测试环境中),它将被归因于顶级 XML 元素。

它说这是可能的,但不知道如何让它发挥作用。 RecordProperty具体用在什么地方?

这是一个基本示例。

gtester.cpp

#include <gtest/gtest.h>
#include <iostream>

struct my_fixture : ::testing::Test
{
    void SetUp() {
        std::cout << "Calling " << __PRETTY_FUNCTION__ << std::endl;

    }
    void TearDown() {
        std::cout << "Calling " << __PRETTY_FUNCTION__ << std::endl;
    }    
};

TEST_F(my_fixture,foo)
{
    ASSERT_EQ(1,1);
}


int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    ::testing::Test::RecordProperty("GlobalProperty", "TopLevel");
    return RUN_ALL_TESTS();
}

编译并link:

g++ -Wall -Wextra -pedantic -o gtester gtester.cpp -pthread -lgtest

运行,XML 输出:

$ ./gtester --gtest_output=xml:./gtester.xml
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from my_fixture
[ RUN      ] my_fixture.foo
Calling virtual void my_fixture::SetUp()
Calling virtual void my_fixture::TearDown()
[       OK ] my_fixture.foo (0 ms)
[----------] 1 test from my_fixture (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (0 ms total)
[  PASSED  ] 1 test.

而XML测试报告为:

$ cat gtester.xml
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="1" failures="0" disabled="0" errors="0" timestamp="2017-11-22T19:24:53" time="0" GlobalProperty="TopLevel" name="AllTests">
  <testsuite name="my_fixture" tests="1" failures="0" disabled="0" errors="0" time="0">
    <testcase name="foo" status="run" time="0" classname="my_fixture" />
  </testsuite>
</testsuites>

其中 <testsuites> 有 属性 GlobalProperty="TopLevel".

查看 gtest 的 source code 我发现函数 RecordProperty() 的以下解释完全回答了您的问题:

Calls to RecordProperty() made during lifespan of the test (from the moment its constructor starts to the moment its destructor finishes) will be output in XML as attributes of the <testcase> element. Properties recorded from fixture's SetUpTestCase() or TearDownTestCase() are logged as attributes of the corresponding <testsuite> element. Calls to RecordProperty() made in the global context (before or after invocation of RUN_ALL_TESTS and from SetUp()/TearDown() method of Environment objects registered with Google Test) will be output as attributes of the <testsuites> element.

此外,以下示例阐明了前面提到的规范:

gtest_example.cpp

#include <gtest/gtest.h>

struct exampleFixture : ::testing::Test {
  static void SetUpTestCase() { RecordProperty("TestsuiteProperty", "I am an attribute of TESTSUITE."); }
  void SetUp() { RecordProperty("TestCaseProperty1", "I am an attribute of TESTCASE, added from exampleFixture::SetUp()"); }
};

TEST_F(exampleFixture, testFeatureX) {
  RecordProperty("TestCaseProperty2", "I am an attribute of TESTCASE, added from testFeatureX()");
  ASSERT_TRUE(true);
}

TEST_F(exampleFixture, testFeatureY) {
  RecordProperty("TestCaseProperty3", "I am an attribute of TESTCASE, added from testFeatureY()");
  ASSERT_TRUE(true);
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);

    ::testing::Test::RecordProperty("TestsuitesProperty", "I am an attribute of TESTSUITES");   

    return RUN_ALL_TESTS();
}

运行 使用命令行参数 --gtest_output=xml:report.xml 编译的可执行文件将生成文件 report.xml:

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="2" failures="0" disabled="0" errors="0" timestamp="2018-02-18T17:11:33" time="0" 
   TestsuitesProperty="I am an attribute of TESTSUITES" name="AllTests">
  <testsuite name="exampleFixture" tests="2" failures="0" disabled="0" errors="0" time="0"
      TestsuiteProperty="I am an attribute of TESTSUITE.">
    <testcase name="testFeatureX" status="run" time="0" classname="exampleFixture"
      TestCaseProperty1="I am an attribute of TESTCASE, added from exampleFixture::SetUp()" 
      TestCaseProperty2="I am an attribute of TESTCASE, added from testFeatureX()" />
    <testcase name="testFeatureY" status="run" time="0" classname="exampleFixture" 
      TestCaseProperty1="I am an attribute of TESTCASE, added from exampleFixture::SetUp()" 
      TestCaseProperty3="I am an attribute of TESTCASE, added from testFeatureY()" />
  </testsuite>
</testsuites>