mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-23 21:20:42 +08:00
R
This commit is contained in:
parent
5921fdb705
commit
8ef1393455
@ -3,31 +3,29 @@
|
||||
[#]: author: "Stephan Avenwedde https://opensource.com/users/hansic99"
|
||||
[#]: collector: "lujun9972"
|
||||
[#]: translator: "toknow-gh"
|
||||
[#]: reviewer: " "
|
||||
[#]: reviewer: "wxy"
|
||||
[#]: publisher: " "
|
||||
[#]: url: " "
|
||||
|
||||
使用 GoogleTest 和 CTest 进行单元测试
|
||||
======
|
||||
进行单元测试可以提高代码质量,并且它不会打断你的工作流。
|
||||
|
||||
> 进行单元测试可以提高代码质量,并且它不会打断你的工作流。
|
||||
|
||||
![Team checklist and to dos][1]
|
||||
|
||||
|
||||
本文是 [使用 CMake 和 VSCodium 搭建构建系统][2] 的后续文章。
|
||||
本文是 [使用 CMake 和 VSCodium 设置一个构建系统][2] 的后续文章。
|
||||
|
||||
在上一篇文章中我介绍了基于 [VSCodium][3] 和 [CMake][4] 配置构建系统。本文我将介绍如何通过 [GoogleTest][5] 和 [CTest][6] 将单元测试集成到这个构建系统中。
|
||||
|
||||
首先克隆 [这个仓库][7],用 VSCodium 打开,切换到 `devops_2` 标签。你可以通过点击 `main` 分支(红框处),然后选择 `devops_2` 标签(黄框处)来进行切换:
|
||||
首先克隆 [这个仓库][7],用 VSCodium 打开,切换到 `devops_2` 标签。你可以通过点击 `main` 分支符号(红框处),然后选择 `devops_2` 标签(黄框处)来进行切换:
|
||||
|
||||
![VSCodium tag][8]
|
||||
|
||||
Stephan Avenwedde (CC BY-SA 4.0)
|
||||
|
||||
或者你可以通过命令行来切换:
|
||||
|
||||
|
||||
```
|
||||
`$ git checkout tags/devops_2`
|
||||
$ git checkout tags/devops_2
|
||||
```
|
||||
|
||||
### GoogleTest
|
||||
@ -40,13 +38,11 @@ GoogleTest 是一个平台无关的开源 C++ 测试框架。单元测试是用
|
||||
* _非致命失败_: 测试失败,但测试继续。
|
||||
* _致命失败_: 测试失败,且测试终止。
|
||||
|
||||
|
||||
致命断言和非致命断言通过不同的宏来区分:
|
||||
|
||||
* `ASSERT_*`: 致命断言,失败时终止。
|
||||
* `EXPECT_*`: 非致命断言,失败时不终止。
|
||||
|
||||
|
||||
谷歌推荐使用 `EXPECT_*` 宏,因为当测试中包含多个的断言时,它允许继续执行。断言有两个参数:第一个参数是测试分组的名称,第二个参数是测试自己的名称。`Generator` 只定义了 `generate(...)` 函数,所以本文中所有的测试都属于同一个测试组:`GeneratorTest`。
|
||||
|
||||
针对 `generate(...)` 函数的测试可以从 [GeneratorTest.cpp][9] 中找到。
|
||||
@ -55,10 +51,7 @@ GoogleTest 是一个平台无关的开源 C++ 测试框架。单元测试是用
|
||||
|
||||
[generate(...)][10] 函数有一个 [std::stringstream][11] 的引用作为输入参数,并且它也将这个引用作为返回值。第一个测试就是检查输入的引用和返回的引用是否一致。
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
TEST(GeneratorTest, ReferenceCheck){
|
||||
const int NumberOfElements = 10;
|
||||
std::stringstream buffer;
|
||||
@ -67,7 +60,6 @@ TEST(GeneratorTest, ReferenceCheck){
|
||||
std::addressof(Generator::generate(buffer, NumberOfElements))
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
在这个测试中我使用 [std::addressof][12] 来获取对象的地址,并用 `EXPECT_EQ` 来比较输入对象和返回对象是否是同一个。
|
||||
@ -76,10 +68,7 @@ TEST(GeneratorTest, ReferenceCheck){
|
||||
|
||||
本测试检查作为输入的 `std::stringstream` 引用中的元素个数与输入参数中指定的个数是否相同。
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
TEST(GeneratorTest, NumberOfElements){
|
||||
const int NumberOfElements = 50;
|
||||
int nCalcNoElements = 0;
|
||||
@ -95,17 +84,13 @@ TEST(GeneratorTest, NumberOfElements){
|
||||
|
||||
EXPECT_EQ(nCalcNoElements, NumberOfElements);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### 乱序重排
|
||||
|
||||
本测试检查随机化引擎是否工作正常。如果连续调用两次 `generate` 函数,应该得到的是两个不同的结果。
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
TEST(GeneratorTest, Shuffle){
|
||||
|
||||
const int NumberOfElements = 50;
|
||||
@ -118,18 +103,13 @@ TEST(GeneratorTest, Shuffle){
|
||||
|
||||
EXPECT_NE(buffer_A.str(), buffer_B.str());
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### 求和校验
|
||||
|
||||
与前面的测试相比,这是一个大体量的测试。它检查 1 到 n 的数值序列的和与乱序重排后的序列的和是否相等。 `generate(...)` 函数应该生成一个 1 到 n 的乱序的序列,这个序列的和应当是不变的。
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
TEST(GeneratorTest, CheckSum){
|
||||
|
||||
const int NumberOfElements = 50;
|
||||
@ -162,7 +142,6 @@ TEST(GeneratorTest, CheckSum){
|
||||
|
||||
EXPECT_EQ(nChecksum_in, nChecksum_out);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
你可以像对一般 C++ 程序一样调试这些测试。
|
||||
@ -176,43 +155,32 @@ TEST(GeneratorTest, CheckSum){
|
||||
如果输入参数是一个正整数,程序应该输出应该是一个数列:
|
||||
|
||||
```
|
||||
|
||||
|
||||
add_test(NAME RegularUsage COMMAND Producer 10)
|
||||
set_tests_properties(RegularUsage
|
||||
PROPERTIES PASS_REGULAR_EXPRESSION "^[0-9 ]+"
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
#### 没有提供参数
|
||||
|
||||
如果没有传入参数,程序应该立即退出并提示错误原因:
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
add_test(NAME NoArg COMMAND Producer)
|
||||
set_tests_properties(NoArg
|
||||
PROPERTIES PASS_REGULAR_EXPRESSION "^Enter the number of elements as argument"
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
#### 参数错误
|
||||
|
||||
当传入的参数不是整数时,程序应该退出并报错。比如给 `Producer` 传入参数 `ABC`:
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
add_test(NAME WrongArg COMMAND Producer ABC)
|
||||
set_tests_properties(WrongArg
|
||||
PROPERTIES PASS_REGULAR_EXPRESSION "^Error: Cannot parse"
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
#### 执行测试
|
||||
@ -222,13 +190,9 @@ set_tests_properties(WrongArg
|
||||
* `-R <测试名称>` : 执行单个测试
|
||||
* `-VV`:打印详细输出
|
||||
|
||||
|
||||
|
||||
测试执行结果如下:
|
||||
|
||||
```
|
||||
|
||||
|
||||
$ ctest -R Usage -VV
|
||||
UpdatecTest Configuration from :/home/stephan/Documents/cpp_testing sample/build/DartConfiguration.tcl
|
||||
UpdateCTestConfiguration from :/home/stephan/Documents/cpp_testing sample/build/DartConfiguration.tcl
|
||||
@ -239,30 +203,21 @@ Updating test list for fixtures
|
||||
Added 0 tests to meet fixture requirements
|
||||
Checking test dependency graph...
|
||||
Checking test dependency graph end
|
||||
|
||||
```
|
||||
|
||||
在这里我执行了名为 `Usage` 的测试。
|
||||
|
||||
它以无参数的方式调用 `Producer`:
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
test 3
|
||||
Start 3: Usage
|
||||
3: Test command: /home/stephan/Documents/cpp testing sample/build/Producer
|
||||
|
||||
```
|
||||
|
||||
输出不匹配 `[^[0-9]+]` 的正则模式,测试未通过。
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
3: Enter the number of elements as argument
|
||||
1/1 test #3. Usage ................
|
||||
|
||||
@ -278,61 +233,47 @@ The following tests FAILED:
|
||||
3 - Usage (Failed)
|
||||
Errors while running CTest
|
||||
$
|
||||
|
||||
```
|
||||
|
||||
如果想要执行所有测试(包括那些用 GoogleTest 生成的),切换到 `build` 目录中,然后运行 `ctest` 即可:
|
||||
|
||||
![CTest run][15]
|
||||
|
||||
Stephan Avenwedde (CC BY-SA 4.0)
|
||||
|
||||
在 VSCodium 中可以通过点击信息栏的黄框处来调用 CTest。如果所有测试都通过了,你会看到如下输出:
|
||||
|
||||
![VSCodium][16]
|
||||
|
||||
Stephan Avenwedde (CC BY-SA 4.0)
|
||||
|
||||
### 使用 Git 钩子进行自动化测试
|
||||
|
||||
目前为止,运行测试是开发者需要额外执行的步骤,那些不能通过测试的代码仍然可能被提交和推送到代码仓库中。利用 [Git 钩子][17] 可以自动执行测试,从而防止有瑕疵的代码被提交。
|
||||
|
||||
切换到 `.git/hooks` 目录,创建 `pre-commit` 文件,复制粘贴下面的代码:
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
#!/usr/bin/sh
|
||||
|
||||
(cd build; ctest --output-on-failure -j6)
|
||||
|
||||
```
|
||||
|
||||
然后,给文件增加可执行权限:
|
||||
|
||||
```
|
||||
`$ chmod +x pre-commit`
|
||||
$ chmod +x pre-commit
|
||||
```
|
||||
|
||||
这个脚本会在提交之前调用 CTest 进行测试。如果有测试未通过,提交过程就会被终止:
|
||||
|
||||
![Commit failed][18]
|
||||
|
||||
Stephan Avenwedde (CC BY-SA 4.0)
|
||||
|
||||
只有所有测试都通过了,提交过程才会完成:
|
||||
|
||||
![Commit succeeded][19]
|
||||
|
||||
Stephan Avenwedde (CC BY-SA 4.0)
|
||||
|
||||
这个机制也有一个漏洞:可以通过 `git commit --no-verify` 命令绕过测试。解决办法是配置构建服务器,这能保证只有正常工作的代码才能被提交,但这又是另一个话题了。
|
||||
|
||||
### 总结
|
||||
|
||||
本文提到的技术实施简单,并且能够帮你快速发现代码中的 bug。做单元测试可以提高代码质量,同时也不会打断你的工作流。GoogleTest 框架提供了丰富的特性以应对各种测试场景,文中我所提到的只是一小部分而已。如果你想进一步了解 GoogleTest,我推荐你阅读 [GoogleTest Primer][20]。
|
||||
|
||||
本文提到的技术实施简单,并且能够帮你快速发现代码中的问题。做单元测试可以提高代码质量,同时也不会打断你的工作流。GoogleTest 框架提供了丰富的特性以应对各种测试场景,文中我所提到的只是一小部分而已。如果你想进一步了解 GoogleTest,我推荐你阅读 [GoogleTest Primer][20]。
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@ -341,14 +282,14 @@ via: https://opensource.com/article/22/1/unit-testing-googletest-ctest
|
||||
作者:[Stephan Avenwedde][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[toknow-gh](https://github.com/toknow-gh)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://opensource.com/users/hansic99
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/todo_checklist_team_metrics_report.png?itok=oB5uQbzf (Team checklist and to dos)
|
||||
[2]: https://opensource.com/article/22/1/devops-cmake
|
||||
[2]: https://linux.cn/article-14249-1.html
|
||||
[3]: https://vscodium.com/
|
||||
[4]: https://cmake.org/
|
||||
[5]: https://github.com/google/googletest
|
||||
|
Loading…
Reference in New Issue
Block a user