前几天发现了一本很好的书 《The Ray Tracer Challenge》 这本书与其它讲编程或讲算法的书不一样的地方在于它全书没有提供可运行的代码,它只提供了伪代码和测试样例。它要求读者跟据书中的讲解和伪代码用读者自己熟悉的语言完成一个光追引擎,并根据书中提供的测试样例来判断有没有正确完成。
书中使用的测试工具是 cucumber 一个 BDD(行为驱动开发) 工具,书中用了 cucumber 的 Gherkin 语言作为书中测试案例的描述语言,这种语言用几乎自然语言的方式来描述测试案例。说到这里读者可能要问了,那你为什么不用 cucumber 呢?标题中不是写着 Google Test 吗?
因为我没装上,或者说我装上了用不了。我主要用 c++ 编程而 cucumber 对 c++ 的支持很不好,我几乎找不到相关的资料。与 java 不同,有关 c 和 c++ 的测试工具很少资料也很少,或许是因为 c 和 c++ 没有那么流行吧。
这里我就以一个例子来说明怎么在 Qt 中使用 Google Test 进行单元测试以及如何设置编译后自动测试。
我录了一个视频把整个过程走了一遍,大家可以看看:
Qt Creator 中使用Google Test进行单元测试
Qt Creator 支持四种测试框架,分别是:QtTest、QtQuickTest、Google Test、Boost Test
我用过其中的 QtTest 和 Google Test ,QtTest 用起来比较麻烦而 Google Test 比较简洁好用。
首先我们要下载 Google Test ,直接到其 GitHub 上下载就可以了,地址为:https://github.com/google/googletest ,下载好后解压放到一个你自己喜欢的目录下。
之后我们需要创建一个 子目录项目 工程,如下图:
子目录项目 顾名思义这个工程是用来包含其他项目的,也就是可以在这一个项目中可以包含多个项目。
创建好后会马上弹出另一个窗口,继续要求新建一个工程(注意标题变成了 新建子项目 ):
向其中添加demo.h
和demo.cpp
向其中分别添加add函数的声明和定义:
之后添加一个测试子工程:
选择 Auto Test Project :
设置 Test suite name 和 Test case name ,前者是你这一组测试的名字,后者是这一组测试中的一个测试案例的名字,这在之后是可以修改的。
这里很重要的一步是填写Googletest的源码目录地址,把之前下载解压好的Google Test的目录填进去就可以了。
好了下面就是生成的测试工程:
其中main.cpp
中已经把 Google Test 的初始化及运行测试的相关代码写好了,我们只需要新建一个cpp
文件编写测试样例就可以了。项目默认会生成一个测试相关的头文件,其中包含了一个测试的例子,可以仿照这个例子写,但注意不要在头文件中写测试,要在cpp
文件中写。
接下来把自动生成的测试案例删除然后创建一个demoTest.cpp
,
在demoTest.cpp
中包含自动生成的头文件tst_add.h
之后就可以在demoTest.cpp
中写测试样例了,但直接这样写出来的测试是没法去测前面写的那个add
函数的,我们需要把 App 工程 中的demo.h
和demo.cpp
添加到 Test 工程 中:
按图上这样把相应的路径添加到工程配置文件 Test.pro 中即可。
之后就可以写测试样例了:
这里我写了一个正确的测试和一个错误的测试。我们可以点击下方工具栏中的 Test Result 或这按 Alt+8 切换到Test result 界面点击绿色的三角运行符号就可以运行测试了:
可以看到它提示第二个测试没有通过,1+2本来等于3而我故意其测试的正确值为4,所以上图提示add(1,2)的值为3而实际应该为4。
Google Test 的一些常用的断言可以在其文档中找到,这里我列举几个常用的断言:
Fatal assertion | Nonfatal assertion | Verifies |
---|---|---|
ASSERT_TRUE(condition); |
EXPECT_TRUE(condition); |
condition is true |
ASSERT_FALSE(condition); |
EXPECT_FALSE(condition); |
condition is false |
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 |
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 |
更多相关设置请查看 Google Test Primer:https://github.com/google/googletest/blob/master/googletest/docs/primer.md
如果以 TDD 的方式开发程序,我们一定希望程序可以在每次编译后自动跑一遍测试。我们可以对项目进行设置,点击左侧边栏中的项目,然后点击 Project Settings 中的 Testing,然后在右侧的 Testing 大字下面把 Global 改成 Custom 并选中下方的 GTest,最后在最下面的 Automatically run tests after build 的下拉框中把 None 改成 All 或 Selected 就可以了。
欢迎关注我的微信公众号 江达小记 ,以及我的B站账号 江达小记