Google Test的高阶使用

Google Test的高阶使用

[TOC]
本文将官网上的高阶用法整理了一下,并在整理好总结了对此优秀开源测试框架的感悟.

总结感悟

  1. 测试相关
    • 建立测试用例的层次
    • 保证测试用例间必须独立互不依赖
    • 测试用例间共享操作与数据(数据安全),节省资源
    • 测试只关注对测试对象的输入与输出,如果无法做到这一点,就需要重构测试代码至符合这一点
    • 注意多线程环境的测试安全
  2. 用户导向的面向对象软件设计
    • 不修改待测对象的代码(但也提供自由度去修改)
    • 所有操作接口化,用户只需要继承接口即可实现测试操作
    • 通过增加运行参数/环境变量增加自由度
    • 大多数测试相关类的生命周期由软件管理,不给用户添加负担
    • 提供便利的输入方式(软件自带+谓词函数)
    • 提供多样化可定制的输出信息
    • 提供泛化层次,例如抽象测试类,参数化测试
    • 特化常用需求,例如死亡测试

更丰富的错误信息输出

使用Bool函数+谓词断言

例子

1
2
3
4
5
6
7
8
9
// 两数是否互为质数
bool MutuallyPrime(int m, int n) { ... }
...
const int a = 3;
const int b = 4;
const int c = 10;
...
EXPECT_PRED2(MutuallyPrime, a, b); // Succeeds
EXPECT_PRED2(MutuallyPrime, b, c); // Fails

失败的错误信息如下:

1
2
3
MutuallyPrime(b, c) is false, where
b is 4
c is 10

包装测试函数的返回值为AssertionResult

一般情况下可以配合谓词断言使用.

1
2
3
4
5
6
7
8
namespace testing {
// 返回一个 AssertionResult 对象(带debug信息),若断言成功的话
AssertionResult AssertionSuccess();

// 返回一个 AssertionResult 对象(带debug信息),若断言失败的话
AssertionResult AssertionFailure();

}

::testing::AssertionResult重载了<<方便流式打印操作.

1
2
3
4
5
6
testing::AssertionResult IsEven(int n) {
if ((n % 2) == 0)
return testing::AssertionSuccess();
else
return testing::AssertionFailure() << n << " is odd";
}

EXPECT_TRUE(IsEven(Fib(4)))输出

1
2
3
Value of: IsEven(Fib(4))
Actual: false (3 is odd)
Expected: true

一般模式

1
2
3
bool IsEven(int n) {
return (n % 2) == 0;
}

输出,不知道为什么错误.

1
2
3
Value of: IsEven(Fib(4))
Actual: false
Expected: true

使用EXPECT_PRED_FORMAT*

例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 返回最小公约数
int SmallestPrimeCommonDivisor(int m, int n) { ... }

// 是否互质
bool MutuallyPrime(int m, int n) { ... }

// 如果不互质,求出最小公约数并进行格式化打印.
testing::AssertionResult AssertMutuallyPrime(const char* m_expr,
const char* n_expr,
int m,
int n) {
if (MutuallyPrime(m, n)) return testing::AssertionSuccess();
//自定义打印
return testing::AssertionFailure() << m_expr << " and " << n_expr
<< " (" << m << " and " << n << ") are not mutually prime, "
<< "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n);
}

...
const int a = 3;
const int b = 4;
const int c = 10;
...
EXPECT_PRED_FORMAT2(AssertMutuallyPrime, a, b); // Succeeds
EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c); // Fails

失败的case的格式化打印如下:

1
b and c (4 and 10) are not mutually prime, as they have a common divisor 2

自定义打印格式

重载<<操作符或者PrintTo()函数,或者使用::testing::PrintToString(x),返回值是std::string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <ostream>

namespace foo {
class Bar {
friend std::ostream& operator<<(std::ostream& os, const Bar& bar) {
return os << bar.DebugString(); // whatever needed to print bar to os
}
friend void PrintTo(const Bar& bar, std::ostream* os) {
*os << bar.DebugString();
};
//类外定义,保证namespace一致
std::ostream& operator<<(std::ostream& os, const Bar& bar) {
return os << bar.DebugString(); // whatever needed to print bar to os
}
void PrintTo(const Bar& bar, std::ostream* os) {
*os << bar.DebugString();}
} // namespace foo
1
2
3
4
vector<pair<Bar, int> > bar_ints = GetBarIntVector();

EXPECT_TRUE(IsCorrectBarIntVector(bar_ints))
<< "bar_ints = " << testing::PrintToString(bar_ints);

断言的放置Assertion Placement

非fatal的断言可以随意防止在项目代码里. fatal断言(FAIL* and ASSERT_*)必须放在返回void的函数里(原因是没使用异常).
但是有例外,构造函数与析构函数虽然也是返回void的但是不能放入fatal断言.
同时,需要注意放入构造函数/析构函数调用的private void-returning method有可能会导致构造/析构不完全.

跳过测试

使用GTEST_SKIP()宏.
两种使用方式:

  1. Test Fixture 里的 SetUp 函数里,所有用到此 Test Fixture 的都会被跳过.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class SkipFixture : public ::testing::Test {
    protected:
    void SetUp() override {
    GTEST_SKIP() << "Skipping all tests for this fixture";
    }
    };

    // Tests for SkipFixture won't be executed.
    TEST_F(SkipFixture, SkipsOneTest) {
    EXPECT_EQ(5, 7); // Won't fail
    }
  2. ::testing::Environment::testing::Test 中直接使用
    1
    2
    3
    4
    TEST(SkipTest, DoesSkip) {
    GTEST_SKIP() << "Skipping single test";
    EXPECT_EQ(0, 1); // Won't fail; it won't be executed
    }

死亡测试

见之前的博文.

Set-Up and Tear-Down的层次

恰如test的三层架构:testsuites -> testsuite -> test.
测试的资源共享也可以在这三个层面发生,想对应地为:
global set-up and tear-down(::testing::Environment) ->
static void SetUpTestSuite() and static void TearDownTestSuite() ->
void SetUp() override and void TearDown() override

每个层级的 SetUp 都发生在整个层次的开始, 整个层次的最后必然会调用 TesrDown 清除数据.

Global Set-Up and Tear-Down

一个test program里全部都会共享的操作/数据可以定义在::testing::Environment的自定义子类里.
自定义格式如下:

1
2
3
4
5
6
7
8
9
10
class Environment : public ::testing::Environment {
public:
~Environment() override {}

// Override this to define how to set up the environment.
void SetUp() override {}

// Override this to define how to tear down the environment.
void TearDown() override {}
};

实例化的操作为:

1
Environment* AddGlobalTestEnvironment(Environment* env);

有几点要注意:

  • 不要手动 delete Environment Google Test 会自动删除.
  • RUN_ALL_TESTS()之前把 Environment 实例化.
  • 最好是在main() 函数里依次初始化上一条的操作.
  • 如果执意使用 gtest_main 来省略 main(), 其中一种实例化 Environment 的方法是将其定义为全局变量,如下:
    1
    2
    testing::Environment* const foo_env =
    testing::AddGlobalTestEnvironment(new FooEnvironment);
    相应地你就必须要自己承担全局变量可能带来的风险:multiple environments from different translation units and the environments have dependencies among them (remember that the compiler doesn’t guarantee the order in which global variables from different translation units are initialized).

Sharing Resources Between Tests in the Same Test Suite

基本形式与Test Fixture差不多,通过例子讲解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class FooTest : public testing::Test {
protected:
// 一个Test Suite内共享的初始化操作
static void SetUpTestSuite() {
// 例如,只需要初始化共享数据一次即可
if (shared_resource_ == nullptr) {
shared_resource_ = new ...;
}
}

// 一个Test Suite内共享的清除善后操作
static void TearDownTestSuite() {
delete shared_resource_;
shared_resource_ = nullptr;
}

// 低层次的SetUp依旧可以定义使用
void SetUp() override { ... }

// 低层次的TearDown依旧可以定义使用
void TearDown() override { ... }

// 静态共享数据,当数据初始化成本较高时
static T* shared_resource_;
};

//紧接着 class 的定义, 此处定义共享数据初值(这里为空)
T* FooTest::shared_resource_ = nullptr;

//后缀_F
TEST_F(FooTest, Test1) {
... you can refer to shared_resource_ here ...
}

TEST_F(FooTest, Test2) {
... you can refer to shared_resource_ here ...
}

除了注释里的注意点外还有一下点需要注意:

  • 由于一个 Test Suite 里的 Test执行顺序是随机的,一定要注意对共享数据的顺序型的操作可能会导致未定义行为.
  • 对于共享的 static 数据注意进行内存管理, Google Test 没有提供支持.
  • 当使用 TEST_P 参数化测试时, 注意把SetUpTestSuite()TearDownTestSuite()声明为public,而不是protected.

参数化测试 Value-Parameterized Tests

试想如下场景:

  • 如果我们想在不同的 command-line flags 下测试代码(最常见的情形是标定参数,其他还有程序的不同模式,例如节能模式,运动模式等).
  • 如果我们想测试不同 interface 下程序/对象的表现(例如不同客户的接口不同).
  • 如果我们想做 data-driven testing ,想看不同数据下程序的表现.
    问题是如何把参数/数据传给 test , 总不能纯手工 copy-paste + swtich case 吧. Google Test 提供了接收参数进行测试的方法.

创建参数化测试类

有两种方式:

  1. 多重继承自:testing::Test 以及 testing::WithParamInterface<T> (pure interface).
  2. 继承封装好的类:testing::TestWithParam<T>

T为任何 copyable 类型. 如果是裸指针,用户需要自己负责管理生命周期.
SetUpTesrDown 必须声明为 public.

用法说明:

  • 类内部通过 GetParam() 成员函数调用传入的参数.
  • 可以传参数到已存的 fixture class.
  • 设置 test suite 时,后缀_P.
  • 可以通过让 test fixture 继承 testing::WithParamInterface<T> 的方式向 test fixture 中传入参数.
  • TEST_P 如果没有 INSTANTIATE_TEST_SUITE_P 会导致测试 suite 结果 FAIL .如果故意设置为空的话,可以使用GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FooTest);特殊标记,不会报 FAIL 进行测试.

代码例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class FooTest :
public testing::TestWithParam<const char*> {
//具体类体,通过 `GetParam()` 成员函数调用传入的参数.
};

// 可以传参数到已存的 fixture class:
class BaseTest : public testing::Test {
...
};
class BarTest : public BaseTest,
public testing::WithParamInterface<const char*> {
...
};

TEST_P(FooTest, DoesBlah) {
// 通过GetParam() method 访问传入参数
EXPECT_TRUE(foo.Blah(GetParam()));
...
}

TEST_P(FooTest, HasBlahBlah) {
...
}

传入参数的方法

通过INSTANTIATE_TEST_SUITE_P宏接收参数.

参数生成器

如果我们有一系列的参数如何传入? 难道还要一个个 typing 进去? Google Test 考虑到常用的参数的可能组合形式, 提供了 test parameters generator.
两个重载函数:

  1. INSTANTIATE_TEST_SUITE_P(InstantiationName,TestSuiteName,param_generator)
  2. INSTANTIATE_TEST_SUITE_P(InstantiationName,TestSuiteName,param_generator,name_generator)
  • InstantiationName: 用TEST_P定义的参数化测试类实例名.
  • TestSuiteName:test suite的名字.
  • param_generator:生成器类型,如下表.
  • name_generator:谓词函数,例如后面的lambda函数,用于根据输入的参数自定义一个具体的test的名称,如果对官方默认的名称命名方式(参见例子)觉得不方便使用的话.

自定义test名称要求:非空,不重复 ASCII 码组成,不包含下划线.

第一种函数的例子:

1
2
3
4
5
INSTANTIATE_TEST_SUITE_P(MeenyMinyMoe,
FooTest,
testing::Values("meeny", "miny", "moe"));
const char* pets[] = {"cat", "dog"};
INSTANTIATE_TEST_SUITE_P(Pets, FooTest, testing::ValuesIn(pets));

INSTANTIATE_TEST_SUITE_P应该放在最 global namespace 里.

生成的test名称分别如下:

1
2
3
4
5
6
7
8
9
10
11
MeenyMinyMoe/FooTest.DoesBlah/0 for "meeny"
MeenyMinyMoe/FooTest.DoesBlah/1 for "miny"
MeenyMinyMoe/FooTest.DoesBlah/2 for "moe"
MeenyMinyMoe/FooTest.HasBlahBlah/0 for "meeny"
MeenyMinyMoe/FooTest.HasBlahBlah/1 for "miny"
MeenyMinyMoe/FooTest.HasBlahBlah/2 for "moe"

Pets/FooTest.DoesBlah/0 for "cat"
Pets/FooTest.DoesBlah/1 for "dog"
Pets/FooTest.HasBlahBlah/0 for "cat"
Pets/FooTest.HasBlahBlah/1 for "dog"
Parameter Generator 行为
Range(begin, end [, step]) 步进 {begin, begin+step, begin+step+step, ...}. 不包括 endstep 默认为 1.
Values(v1, v2, ..., vN) 组合为元组 {v1, v2, ..., vN}.
ValuesIn(container) or ValuesIn(begin,end) C数组,STL容器,迭代器对象
Bool() {false, true}.
Combine(g1, g2, ..., gN) 对于给定的 n个 generators g1g2, …, gN进行笛卡尔乘积得到std::tuple.

name_generator:必须接受TestParamInfo<class ParamType>入参,返回值为std::string. 例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class MyTestSuite : public testing::TestWithParam<int> {};

TEST_P(MyTestSuite, MyTest)
{
std::cout << "Example Test Param: " << GetParam() << std::endl;
}

INSTANTIATE_TEST_SUITE_P(MyGroup, MyTestSuite, testing::Range(0, 10),
testing::PrintToStringParamName());

enum class MyType { MY_FOO = 0, MY_BAR = 1 };

class MyTestSuite : public testing::TestWithParam<std::tuple<MyType, std::string>> {
};

//以下传参,先通过combine组合两个数据结构为std::tuple,然后通过lambda的谓词函数,组合tuple里的字符串为想要的名字.
INSTANTIATE_TEST_SUITE_P(
MyGroup, MyTestSuite,
testing::Combine(
testing::Values(MyType::MY_FOO, MyType::MY_BAR),
testing::Values("A", "B")),
[](const testing::TestParamInfo<MyTestSuite::ParamType>& info) {
std::string name = absl::StrCat(
std::get<0>(info.param) == MyType::MY_FOO ? "Foo" : "Bar",
std::get<1>(info.param));
absl::c_replace_if(name, [](char c) { return !std::isalnum(c); }, '_');
return name;
});

这些参数有啥用?可以使用--gtest_filter过滤特定的测试用例.

抽象测试Abstract Tests

定义一个测试的接口,封装起来用于多个程序的测试,也就是所谓的测试驱动开发TDD.

实施思路如下:

  1. .h头文件里定义 test fixture class.
  2. .cpp文件里定义TEST_P,同时包含.h头文件.
  3. 在测试项目中,包含.h,使用INSTANTIATE_TEST_SUITE_P()初始化参数化测试实例开展测试.

测试 private属性的代码

理论上对任何对象的测试(类,函数,一段程序)都应当当作黑盒测试,即从用户的角度测试.
但是调试阶段我们还是要深入对象内部或者根本没对象的代码段去测试.因此分为2种场景:

static 非成员函数, namespace 函数

  • 方法1: #include 整个 .cc file 到测试文件中 *_test.cc .
  • 方法2: 把这些函数放入*-internal.h 内部测试专用的头文件,测试文件在 include 进去.

private/protected成员函数

  • 方法1: 将 test fixture 声明为待测类的友元.但是主要即便 test fixture 是待测类的友元,不代表 test fixture 的子类(实际测试类)自动是待测类的友元.需要手动设置.
  • 方法2: 应用Pimpl模式(参考),将待测类重构到*-internal.h中.
  • 方法3: 将test suite 打桩到待测类中,如下.注意待测类与测试 suite 必须在同一个 namespace 下.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    FRIEND_TEST(TestSuiteName, TestName);

    namespace my_namespace {

    class Foo {
    friend class FooTest;
    FRIEND_TEST(FooTest, Bar);
    FRIEND_TEST(FooTest, Baz);
    ... definition of the class Foo ...
    };

    } // namespace my_namespace

    namespace my_namespace {

    class FooTest : public testing::Test {
    protected:
    ...
    };

    TEST_F(FooTest, Bar) { ... }
    TEST_F(FooTest, Baz) { ... }

    } // namespace my_namespace

以上的很多方法,例如*-internal.h必须与生产过程解偶,只用于测试.

捕获失败异常

Google Test 中不使用异常机制,那如何测试expected failure?
gtest/gtest-spi.h包含如下宏:

  • EXPECT_FATAL_FAILURE(statement, substring);
  • EXPECT_NONFATAL_FAILURE(statement, substring);
  • EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substring);
  • EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substring);

运行时生成测试用例(Registering tests programmatically)

一般测试都是静态地测试,即确定输入,编译时固定好测试用例,运行测试时即可得到测试结果.那如果有测试运行时才能确定的测试用例怎么办? Google Test 提供了::testing::RegisterTest方便 runtime 确定测试用例.

模型如下:

1
2
3
4
template <typename Factory>
TestInfo* RegisterTest(const char* test_suite_name, const char* test_name,
const char* type_param, const char* value_param,
const char* file, int line, Factory factory);

其中:

  • Factory 是一个 move-constructible 的生产 Fixture 的函数对象.factory对象的 signature of the callable is Fixture*().
  • test_suite_nameFixture 对象的ID.

具体使用案例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class MyFixture : public testing::Test {
public:.
static void SetUpTestSuite() { ... }
static void TearDownTestSuite() { ... }
void SetUp() override { ... }
void TearDown() override { ... }
};

class MyTest : public MyFixture {
public:
explicit MyTest(int data) : data_(data) {}
void TestBody() override { ... }

private:
int data_;
};

void RegisterMyTests(const std::vector<int>& values) {
for (int v : values) {
testing::RegisterTest(
"MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr,
std::to_string(v).c_str(),
__FILE__, __LINE__,
// Important to use the fixture type as the return type here.
[=]() -> MyFixture* { return new MyTest(v); });
}
}
...
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
std::vector<int> values_to_test = LoadValuesFromConfig();
RegisterMyTests(values_to_test);
...
return RUN_ALL_TESTS();
}

get测试的信息(各层次)

如下可以获取正在执行的测试用例的信息.

1
2
3
4
5
6
7
8
// Gets information about the currently running test.
// Do NOT delete the returned object - it's managed by the UnitTest class.
const testing::TestInfo* const test_info =
testing::UnitTest::GetInstance()->current_test_info();

printf("We are in test %s of test suite %s.\n",
test_info->name(),
test_info->test_suite_name());

UnitTest 单例对象中使用 GetInstance()->current_test_info() 得到当前测试的 TestInfo.

::testing::TestInfo里包含了test_suite_name, name, type_param, value_param, file, line等一个测试用例的具体信息.
参见:TestInfo.

监听测试API

Google Test 提供了 event listener API, 可以用来监听如下过程:

  • 整个测试program的开始与结束
  • test suite 状态
  • test method 状态
    用途例子:
  • 替换默认的XML报告输出格式,甚至可以输出为GUI的格式.
  • 设置资源泄漏的 checkpoints 等.

有2个 hanlder 函数:

  • testing::TestEventListener: 纯虚类,interface类.
  • testing::EmptyTestEventListener: 提供了 empty 的函数实现.
    处理 event 的 hanlder 函数接受的入参类型如下:
  • UnitTest reflects the state of the entire test program,
  • TestSuite has information about a test suite, which can contain one or more tests,
  • TestInfo contains the state of a test, and
  • TestPartResult represents the result of a test assertion.

对监听类的定义例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MinimalistPrinter : public testing::EmptyTestEventListener {
// 在整个测试项目开始前监听一次
void OnTestStart(const testing::TestInfo& test_info) override {
printf("*** Test %s.%s starting.\n",
test_info.test_suite_name(), test_info.name());
}

// 检测测试结果.
void OnTestPartResult(const testing::TestPartResult& test_part_result) override {
printf("%s in %s:%d\n%s\n",
test_part_result.failed() ? "*** Failure" : "Success",
test_part_result.file_name(),
test_part_result.line_number(),
test_part_result.summary());
}

//在整个测试项目结束前监听一次
void OnTestEnd(const testing::TestInfo& test_info) override {
printf("*** Test %s.%s ending.\n",
test_info.test_suite_name(), test_info.name());
}
};

main()函数调用上述监听类

通过初始化一个监听类的容器,并 new 出一个监听类,添加进入即可.注意 new 后不需要手动 delete, 系统会自动释放资源.

1
2
3
4
5
6
7
8
9
10
11
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
// Gets hold of the event listener list.
testing::TestEventListeners& listeners =
testing::UnitTest::GetInstance()->listeners();
//如果觉得监听结果与系统自带的输出重复,可以屏蔽系统自带的输出,实现如下.
delete listeners.Release(listeners.default_result_printer());
// Adds a listener to the end. googletest takes the ownership.
listeners.Append(new MinimalistPrinter);
return RUN_ALL_TESTS();
}

对failure-raising event 的限制

failure-raising 指的是 EXPECT_*()ASSERT_*()FAIL(),即有可能报错的断言.

  • 不能在OnTestPartResult()生成failure 断言,否则会导致OnTestPartResult()循环被调用.
  • OnTestPartResult()本身

控制测试程序执行选项

在编译得出的可执行文件后的选项.

选项 说明
--help -h -? /? help 文档
--gtest_list_tests 列出所有的测试用例(树状)
--gtest_filter 过滤用例,有通配符规则
--gtest_fail_fast 遇到第一个 FAIL 就停止测试
--gtest_also_run_disabled_tests 等同于GTEST_ALSO_RUN_DISABLED_TESTS宏设置,不为0时执行disabled测试(前缀DISABLED_的测试)
--gtest_repeat 设置重复测试次数
--gtest_shuffle 等同于设置GTEST_SHUFFLE为1,使得测试用例执行顺序随机
--gtest_random_seed=SEED 设置随机测试的随机种子(不使用默认种子)
--gtest_color 等同于GTEST_COLOR,值为yes/no控制终端输出是否为彩色.TERM可以设置为风格:xterm or xterm-color
--gtest_brief=1 等同于GTEST_BRIEF为1,选择只输出 FAIL 信息,过滤 SUCCESS
--gtest_print_time=0 等同于GTEST_PRINT_TIME为0,选择不输出时间信息
--gtest_print_utf8=0 等同于GTEST_PRINT_UTF8为0,输出字符串不为UTF8格式
--gtest_output 等同于GTEST_OUTPUT. "xml:path_to_output_file":输出xml格式报告,"json:path_to_output_file":输出json格式

disable用例

1
2
3
4
5
6
7
// Tests that Foo does Abc.
TEST(FooTest, DISABLED_DoesAbc) { ... }

class DISABLED_BarTest : public testing::Test { ... };

// Tests that Bar does Xyz.
TEST_F(DISABLED_BarTest, DoesXyz) { ... }

自动生成测试报告 xml / json

RecordProperty("key", value)命令可以组成xml的标签与内容, value是 string 或者 int .用法如下

1
2
3
4
TEST_F(WidgetUsageTest, MinAndMaxWidgets) {
RecordProperty("MaximumWidgets", ComputeMaxUsage());
RecordProperty("MinimumWidgets", ComputeMinUsage());
}

输出格式如下

1
2
3
...
<testcase name="MinAndMaxWidgets" status="run" time="0.006" classname="WidgetUsageTest" MaximumWidgets="12" MinimumWidgets="9" />
...

注意:

  • TEST外使用 RecordProperty 需要加上::testing::Test::.
  • key 不能与 name, status, time, classname, type_param, value_param重复
  • RecordPropertyTETS使用的化,生成的标签会是top-level XML element.

生成的xml报告结构

1
2
3
4
5
6
7
8
9
<testsuites name="AllTests" ...>
<testsuite name="test_case_name" ...>
<testcase name="test_name" ...>
<failure message="..."/>
<failure message="..."/>
<failure message="..."/>
</testcase>
</testsuite>
</testsuites>

更具体的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" errors="0" time="0.035" timestamp="2011-10-31T18:52:42" name="AllTests">
<testsuite name="MathTest" tests="2" failures="1" errors="0" time="0.015">
<testcase name="Addition" status="run" time="0.007" classname="">
<failure message="Value of: add(1, 1)&#x0A; Actual: 3&#x0A;Expected: 2" type="">...</failure>
<failure message="Value of: add(1, -1)&#x0A; Actual: 1&#x0A;Expected: 0" type="">...</failure>
</testcase>
<testcase name="Subtraction" status="run" time="0.005" classname="">
</testcase>
</testsuite>
<testsuite name="LogicTest" tests="1" failures="0" errors="0" time="0.005">
<testcase name="NonContradiction" status="run" time="0.005" classname="">
</testcase>
</testsuite>
</testsuites>
  • <testsuites>:整个测试项目.
  • <testsuite>:单个的测试suite.
  • <testcase>:一个测试case.
  • tests:各层级的测试数目
  • failures:各层级的失败数目
  • time:测试运行时间长度
  • timestamp:时间戳

生成 JSON 格式例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
{
"tests": 3,
"failures": 1,
"errors": 0,
"time": "0.035s",
"timestamp": "2011-10-31T18:52:42Z",
"name": "AllTests",
"testsuites": [
{
"name": "MathTest",
"tests": 2,
"failures": 1,
"errors": 0,
"time": "0.015s",
"testsuite": [
{
"name": "Addition",
"status": "RUN",
"time": "0.007s",
"classname": "",
"failures": [
{
"message": "Value of: add(1, 1)\n Actual: 3\nExpected: 2",
"type": ""
},
{
"message": "Value of: add(1, -1)\n Actual: 1\nExpected: 0",
"type": ""
}
]
},
{
"name": "Subtraction",
"status": "RUN",
"time": "0.005s",
"classname": ""
}
]
},
{
"name": "LogicTest",
"tests": 1,
"failures": 0,
"errors": 0,
"time": "0.005s",
"testsuite": [
{
"name": "NonContradiction",
"status": "RUN",
"time": "0.005s",
"classname": ""
}
]
}
]
}

分布式执行测试

分布式执行测试sharding, 每台机器叫在 shard.
暂时不会用到这个技术.略过.

类型测试以及类型参数化测试

TYPED_TEST以及TYPED_TEST_SUITE测试类型.
TYPED_TEST_P以及TYPED_TEST_SUITE_P测试参数化的类型.
可以测试数据的类型.略过,用时查阅.

子程序中使用断言(Using Assertions in Sub-routines)

Google 提供此功能,后续有需求再总结查阅.

作者

cx

发布于

2021-12-10

更新于

2022-07-16

许可协议