前幾天發現了一本很好的書 《The Ray Tracer Challenge》 這本書與其它講編程或講算法的書不一樣的地方在於它全書沒有提供可運行的代碼,它只提供了僞代碼和測試樣例。它要求讀者跟據書中的講解和僞代碼用讀者自己熟悉的語言完成一個光追引擎,並根據書中提供的測試樣例來判斷有沒有正確完成。
書中使用的測試工具是 cucumber 一個 BDD(行爲驅動開發) 工具,書中用了 cucumber 的 Gherkin 語言作爲書中測試案例的描述語言,這種語言用幾乎自然語言的方式來描述測試案例。說到這裏讀者可能要問了,那你爲什麼不用 cucumber 呢?標題中不是寫着 Google Test 嗎?
因爲我沒裝上,或者說我裝上了用不了。我主要用 c++ 編程而 cucumber 對 c++ 的支持很不好,我幾乎找不到相關的資料。與 java 不同,有關 c 和 c++ 的測試工具很少資料也很少,或許是因爲 c 和 c++ 沒有那麼流行吧。
在Qt Creator中使用Google Test
這裏我就以一個例子來說明怎麼在 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 ,下載好後解壓放到一個你自己喜歡的目錄下。
之後我們需要創建一個 子目錄項目 工程,如下圖:
子目錄項目 顧名思義這個工程是用來包含其他項目的,也就是可以在這一個項目中可以包含多個項目。
創建好後會馬上彈出另一個窗口,繼續要求新建一個工程(注意標題變成了 新建子項目 ):
這裏爲了演示方便,我創建一個最簡單的c++程序:
向其中添加demo.h
和demo.cpp
向其中分別添加add函數的聲明和定義:
之後添加一個測試子工程:
選擇 Auto Test Project :
選擇使用 Google Test :
設置 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站賬號 江達小記