本篇主要介绍Google Test(有时也称为gtest)的相关基础知识。
1 Why googletest
此处引用 google test 在 GitHub 上的介绍:
googletest helps you write better C++ tests.
googletest is a testing framework developed by the Testing Technology team with Google's specific requirements and constraints in mind. No matter whether you work on Linux, Windows, or a Mac, if you write C++ code, googletest can help you. And it supports any kind of tests, not just unit tests.
googletest 是一个由 Google 的测试技术团队开发的测试框架,它考虑到了谷歌的特定需求和限制。无论你使用的是 Linux、Windows 还是 Mac,只要你编写 C++ 代码,googletest 都可以帮到你。它支持任何类型的测试,不只是单元测试。
2 相关知识
2.1 术语说明
Test: 测试;
Test Case: 测试用例;
Test Suite: 测试套件。
由于某些历史原因,GoogleTest使用 Test Case 来分组相关的测试,即将相关的Test 归为一组;然而,当前的出版物包括 ISTQB(International Software Testing Qualifications Board,国际软件测试资格委员会) 和很多关于软件质量的书籍都使用 Test Suite 替换 Test Case表示这一含义;而 googletest 中的 Test 则对应 ISTQB 的 Test Case。总结后,即下表内容:
Meaning | Google Test term | ISTQB term |
---|---|---|
Exercise a particular program path with specific input values and verify the result 以特定输入值执行一个特定的程序路径并验证结果 | Test | Test Case |
A set of several tests related to one component | Test Case | Test Suite |
2.2 基本概念
使用 googletest,最先写的就是断言(assertion)。断言是一种检查某个条件是否为真的描述。断言的结果可以是成功、非致命失败、致命失败。当致命失败发生时,当前函数将会终止;而断言的其他结果则不会有此效果。
Test 使用断言来判断测试代码的行为:如果一个 Test崩溃了或者出现了一个失败的断言,则该 Test 就失败了;反之,它就是成功的。
Test case 包括一个或多个 Test。我们应当把 Test 打包、分组,放入 Test Case 中,以便测试代码的结构更加清晰。当一个 Test Case 中的多个Test 需要共享对象和子程序时,我们可以把这些共享内容放入一个(test fixture)类中。
一个测试程序可以包含多个 Test Case。
2.3 断言
googletest 的断言是类似函数调用的宏。
我们可以通过编写相关的断言,来测试类或函数的行为。如果断言失败了,googletest 将打印该断言的源文件及行号信息,以及该失败信息。我们也可以定制 googletest 的失败信息,它们将被加在 googletest 的消息的后面。
当前,有两种断言可供我们使用,它们测试相同的事情但对当前函数具有不同的影响:
ASSERT_*
:致命断言,当断言失败时,产生致命失败,并终止当前函数;EXPECT_*
:非致命断言,当断言失败时,产生非致命失败,并且不会终止当前函数。
通常,我们都会选择EXPECT_*
,因为它能让我们在一次测试中测试出更多的失败情况。不过,如果我们想要在出现失败的测试时立即终止程序,则要选择ASSERT_*
。
注意:因为ASSERT_*
会在失败时立即终止函数,那么就可能跳过后面程序中进行清理工作的代码,由此可能会产生内存泄露。所以我们在使用ASSERT_*
时,要留心检查堆内存,防止内存泄露。
为了提供定制的失败消息,简单的使用<<
操作符,或一串这种操作符,把它送进宏。一个例子如下:
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";
for (int i = 0; i < x.size(); ++i) {
EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}
任何可以被送给 ostream
的东西都可以被送进断言的宏。特别是,C 字符串和 string
对象。如果宽字符串(wchar_t*
, Windows 上 UNICODE
模式的 TCHAR*
,或 std::wstring
)被送进断言,它将在打印时被转换为 UTF-8
。
2.3.1 常见断言语句
【基本断言】:
这些断言执行基本的 true/false 条件测试。
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); | condition is true |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); | condition is false |
记住,当它们失败时,ASSERT_*
产生一个致命错误,并从当前函数退出,EXPECT_*
则产生一个非致命错误,并允许函数继续运行。任何一种情况下,断言失败意味着包含它的测试失败。
【二元断言】:
二元断言对两个值的比较进行判断。
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_EQ(val1, val2); | EXPECT_EQ(val1, val2); | val1 == val2 |
ASSERT_NE(val1, val2); | EXPECT_NE(val1, val2); | val1 != val2 |
ASSERT_LT(val1, val2); | EXPECT_LT(val1, val2); | val1 < val2 |
ASSERT_LE(val1, val2); | EXPECT_LE(val1, val2); | val1 <= val2 |
ASSERT_GT(val1, val2); | EXPECT_GT(val1, val2); | val1 > val2 |
ASSERT_GE(val1, val2); | EXPECT_GE(val1, val2); | val1 >= val2 |
备注:
==
:EQual
!=
: Not Equal
<
: Less Than
<=
:Less Equal
>
: Greater Than
>=
:Greater Equal
注意:
- 值参数必须是断言的比较操作符可比较的,否则将报出编译错误。
- 我们常要求参数支持
<<
操作符,以便于把它们送进ostream
,但这不再是必须的。如果支持<<
,则在断言失败时它将被调用来打印参数;否则 googletest 将尝试以它能找到的最好的方式打印它们。更多细节及如何定制参数的打印的信息,请参考文档。 - 当可能时,
ASSERT_EQ(actual, expected)
好于ASSERT_TRUE(actual == expected)
,因为它在失败时告诉你actual
和expected
的值 ASSERT_EQ()
对指针执行相等性操作。如果使用两个 C 字符串,它测试它们是否位于相同的内存位置,而不是它们是否具有相同的值。因此,如果你想比较 C 字符串的值(比如const char*
),使用ASSERT_STREQ()
,它将在后面描述。特别地,要断言 C 字符串是NULL
,则使用ASSERT_STREQ(c_string, NULL)
,如果支持 c++11 则考虑使用ASSERT_EQ(c_string, nullptr)
。要比较两个string
对象,你应该使用ASSERT_EQ
。- 当执行指针比较时使用
*_EQ(ptr, nullptr)
和*_NE(ptr, nullptr)
而不是*_EQ(ptr, NULL)
和*_NE(ptr, NULL)
。这是因为nullptr
是类型安全的而NULL
不是。
【字符串断言】:
这一组断言比较两个 C 字符串。如果你想比较两个 string
对象,则使用 EXPECT_EQ
,EXPECT_NE
,等等。
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_STREQ(str1, str2); | EXPECT_STREQ(str1, str2); | the two C strings have the same content |
ASSERT_STRNE(str1, str2); | EXPECT_STRNE(str1, str2); | the two C strings have different contents |
ASSERT_STRCASEEQ(str1, str2); | EXPECT_STRCASEEQ(str1, str2); | the two C strings have the same content, ignoring case |
ASSERT_STRCASENE(str1, str2); | EXPECT_STRCASENE(str1, str2); | the two C strings have different contents, ignoring case |
注意:
- 断言名字中的
"CASE"
意味着忽略大小写。 NULL
指针和空字符串被认为是不同的。*STREQ*
和*STRNE*
也接受宽 C 字符串(wchar_t*
)。如果比较两个宽字符串失败,则它们的值将以UTF-8
窄字符串的形式打印。
另请参阅: 更多字符串比较技巧(子字符串,前缀,后缀,和正则表达式匹配,比如),请参考高级 googletest 指南的这个部分。
参考:
“Googletset入门”
“Google Test 介绍(一)”
“Google Test 介绍(二)”