引言:为什么选择 GoogleTest?
GoogleTest 帮助你编写更好的 C++ 测试。
GoogleTest 是由 Google 的测试技术团队开发的测试框架,它考虑了 Google 的特定需求和约束条件。无论你是在 Linux、Windows 还是 Mac 上工作,如果你编写 C++ 代码,GoogleTest 都可以为你提供帮助。而且,它支持 任何 类型的测试,而不仅仅是单元测试。
那么,什么是好的测试,GoogleTest 又是如何融入其中的呢?我们相信:
1. 测试应该是独立的且可重复的。如果一个测试的成功或失败取决于其他测试,那么调试起来会非常麻烦。GoogleTest 通过在不同的对象上运行每个测试来隔离它们。当一个测试失败时,GoogleTest 允许你单独运行它,以便快速调试。
2. 测试应该是有组织的,并反映被测试代码的结构。GoogleTest 将相关的测试分组到测试套件中,这些测试套件可以共享数据和子例程。这种常见的模式易于识别,使得测试易于维护。当人们切换项目并开始处理新的代码库时,这种一致性尤其有帮助。
3. 测试应该是可移植的且可重用的。Google 有许多代码是与平台无关的,其测试也应该与平台无关。GoogleTest 可以在不同的操作系统上运行,支持不同的编译器,无论是否使用异常,因此 GoogleTest 测试可以与各种配置一起工作。
4. 当测试失败时,它们应该提供尽可能多的关于问题的信息。GoogleTest 不会在第一个测试失败时停止。相反,它只会停止当前测试,并继续进行下一个测试。你还可以设置在报告非致命失败后继续执行当前测试的测试。因此,你可以在一次运行 – 编辑 – 编译周期中检测并修复多个错误。
5. 测试框架应该解放测试编写者,让他们专注于测试内容,而不是家务琐事。GoogleTest 自动跟踪所有定义的测试,并且不需要用户列出它们才能运行。
6. 测试应该是快速的。使用 GoogleTest,你可以在测试之间重用共享资源,并且只需支付一次设置/拆除的费用,而不会使测试相互依赖。
由于 GoogleTest 基于流行的 xUnit 架构,如果你之前使用过 JUnit 或 PyUnit,你会感到非常熟悉。如果没有,学习基础知识并开始使用大约需要 10 分钟。那么,让我们开始吧!
注意术语的混淆
注意:由于“测试”“测试用例”和“测试套件”等术语的不同定义,可能会引起一些混淆,因此请注意不要误解这些术语。
历史上,GoogleTest 开始使用“测试用例”(Test Case)这个术语来分组相关的测试,而目前的出版物(包括国际软件测试资格委员会(ISTQB)的材料以及各种关于软件质量的教科书)则使用“测试套件”(Test Suite)这个术语。
与之相关的术语“测试”(Test),在 GoogleTest 中的使用方式对应于 ISTQB 等的“测试用例”(Test Case)。
“测试”(Test)这个术语通常足够宽泛,包括 ISTQB 对“测试用例”(Test Case)的定义,因此在这里并不是什么大问题。但是,“测试用例”(Test Case)在 Google Test 中的使用是矛盾的,因此会引起混淆。
GoogleTest 最近开始用“测试套件”(Test Suite)替换“测试用例”(Test Case)。首选的 API 是“TestSuite”,而较旧的“TestCase”API 正在逐渐被弃用并重构掉。
因此,请注意这些术语的不同定义:
含义 GoogleTest 术语 ISTQB 术语
使用特定输入值运行特定程序路径并验证结果 TEST() 测试用例(Test Case)
基本概念
使用 GoogleTest 时,你首先需要编写 断言(Assertions),断言是检查某个条件是否为真的语句。断言的结果可以是 成功、非致命失败 或 致命失败。如果发生致命失败,它将终止当前函数的执行;否则程序将继续正常运行。
测试(Tests)使用断言来验证被测试代码的行为。如果测试崩溃或断言失败,则测试 失败;否则测试 成功。
测试套件(Test Suite)包含一个或多个测试。你应该将测试分组到测试套件中,使其反映被测试代码的结构。当多个测试需要共享对象和子例程时,你可以将它们放入一个 测试夹具(Test Fixture)类中。
一个 测试程序(Test Program)可以包含多个测试套件。
接下来,我们将解释如何编写测试程序,从单个断言级别开始,逐步构建到测试和测试套件。
断言
GoogleTest 断言是类似于函数调用的宏。你可以通过断言来测试类或函数的行为。当断言失败时,GoogleTest 会打印断言所在的源文件和行号位置,以及失败消息。你还可以提供自定义的失败消息,它将附加到 GoogleTest 的消息中。
断言成对出现,它们测试相同的内容,但对当前函数有不同的影响。`ASSERT_*` 版本在失败时会生成致命失败,并 终止当前函数。`EXPECT_*` 版本会生成非致命失败,不会终止当前函数。通常建议使用 `EXPECT_*`,因为它们允许在单个测试中报告多个失败。但是,如果在断言失败时继续执行没有意义,你应该使用 `ASSERT_*`。
由于失败的 `ASSERT_*` 会立即从当前函数返回,可能会跳过后面的清理代码,因此可能会导致内存泄漏。根据泄漏的性质,可能值得修复,也可能不值得修复——所以如果你在断言错误之外还收到堆检查器错误,请注意这一点。
为了提供自定义失败消息,只需使用 `<<` 运算符(或一系列这样的运算符)将其流式传输到宏中。例如,使用 `ASSERT_EQ` 和 `EXPECT_EQ` 宏来验证值是否相等: ```cpp 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。 GoogleTest 提供了一系列断言,用于以各种方式验证代码的行为。你可以检查布尔条件、根据关系运算符比较值、验证字符串值、浮点值等。甚至还有断言可以让你通过提供自定义谓词来验证更复杂的状态。有关 GoogleTest 提供的完整断言列表,请参阅 [断言参考](https://google.github.io/googletest/reference/assertions.html)。 简单测试 要创建一个测试: 1. 使用 `TEST()` 宏定义并命名一个测试函数。这些是普通的 C++ 函数,不返回任何值。 2. 在此函数中,除了你想要包含的任何有效 C++ 语句外,使用各种 GoogleTest 断言来检查值。 3. 测试的结果由断言决定;如果测试中的任何断言失败(无论是致命的还是非致命的),或者测试崩溃,则整个测试失败。否则,它成功。 ```cpp TEST(TestSuiteName, TestName) { ... test body ... } ``` `TEST()` 的参数从一般到具体。第一个 参数是测试套件的名称,第二个 参数是测试套件中测试的名称。两个名称都必须是有效的 C++ 标识符,并且不应包含任何下划线(`_`)。测试的 全名 由其包含的测试套件和其单独的名称组成。不同测试套件中的测试可以具有相同的单独名称。 例如,让我们来看一个简单的整数函数: ```cpp int Factorial(int n); // Returns the factorial of n ``` 这个函数的测试套件可能如下所示: ```cpp // Tests factorial of 0. TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(Factorial(0), 1); } // Tests factorial of positive numbers. TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(Factorial(1), 1); EXPECT_EQ(Factorial(2), 2); EXPECT_EQ(Factorial(3), 6); EXPECT_EQ(Factorial(8), 40320); } ``` GoogleTest 按测试套件分组显示测试结果,因此逻辑上相关的测试应该在同一个测试套件中;换句话说,它们的 `TEST()` 的第一个参数应该相同。
未经允许不得转载:海淘实验室 » GoogleTest 入门指南

海淘实验室
VPS(虚拟专用服务器)新手入门指南







