最近寫python用unittest模組做單元測試,才發現自己過去寫c++居然都是手工測試。查了一番資料之後,發現catch和valgrind這兩個工具可以很好地滿足需求。
測試c++程式時,我們通常會在意兩件事:
執行結果是否正確?
是否發生了記憶體洩漏?
第一件事所有程式語言都需要在意,通常是給程式各種輸入,檢驗輸出的正確性,catch是乙個輕巧的單元測試框架,學習起來非常容易;
第二件事應該是c/c++獨有的,需要跟蹤執行時動態分配的記憶體,雖然可以自行過載new/delete運算子做到這一點,但valgrind可以為我們檢測絕大多數記憶體相關問題(包括記憶體洩漏、陣列越界、使用未初始化變數等)。
結束了,比把大象裝到冰箱裡還少一步。
然後安裝valgrind只要一步:
apt-get install valgrind
正好刷leetcode寫到了trie,就修改一下拿它做例子,不感興趣可以直接跳到第三節catch的使用方法。
trie又叫字典樹、字首樹(prefix tree),是一種用來實現快速檢索的多叉樹。簡單地講,從根節點出發經過的路徑確定了乙個字串,每個節點有標記當前字串是否為有效單詞。比如記當前字串為s,走ten那條路徑的話:
選擇」t」,s從「」變成「t」,不是有效單詞;
選擇「e」,s從「t」變成「te」,不是有效單詞;
選擇「n」,s從「te」變成「ten」,是有效單詞。
首先來看trie中節點trienode的定義:
typedef
struct trienode ;
} trienode;
trienode用bool值completed標記當前字串是否為有效單詞,用children實現字元到後繼trienode的對映。比如上圖的根節點,children裡就會有「t」、「a」、「i」三項。
然後來看trie的定義:
class trie ;
話不多說,直接看使用catch的測試檔案test.cpp:
#include
#include
#include
"trie.h"
#define catch_config_main
#include
"catch.hpp"
using namespace std;
test_case("testing trie")
section("search a nonexistent word.")
// tear down
delete t;
}
除去trivial的#include 「catch.hpp」外,使用#define catch_config_main表示讓catch自動提供main函式,執行在test_case中設計的測試。
簡單地講,每個test_case由三部分組成,set up、sections和tear down,set up是各個section都需要的準備工作,tear down是各個section都需要的清理工作,set up和tear down對於每個section都會執行一遍。
比如有乙個test_case:
test_case
真正執行時就是:set up->case 1->tear down->set up->case 2->tear down。
此處test_case裡的兩個section,第乙個section是查詢trie中存在的單詞,第二個section是查詢trie中不存在的單詞。require是catch提供的巨集,相當於assert,檢驗表示式是否成立。
寫好makefile檔案:
hdrs = $(wildcard *.h)
srcs = $(wildcard *.cpp)
objs = $(patsubst %.cpp, %.o, $(srcs))
deps = $(patsubst %.cpp, %.d, $(srcs))
target = test
cxx = g++
$(target): $(objs)
$(cxx) -g -o $(target) $(objs)
-include $(deps)
%.o: %.cpp
$(cxx) -c -mmd -std=c++11
$<
.phony: clean
clean:
-rm *.o
-rm *.d
-rm *.gch
-rm $(target)
make之後執行test,可以看到:
修改search方法,使得總是返回true,那麼第乙個section仍然正確,第二個section出錯:
catch告訴我們在第二個section,也就是「search a nonexistent word」時出錯,失敗的原因是實際search結果為true
valgrind其實是一套工具的集合,可以用–tool引數指定使用哪種工具,預設使用的是記憶體檢測工具memcheck。valgrind使用更加簡單,比如編譯鏈結後的可執行檔案是test,那麼檢測記憶體洩漏情況只需使用命令:
valgrind leak-check=yes ./test
注意要用./test而不是test。
注釋掉test.cpp裡tear down部分,那麼構造的trie不會被釋放,用catch測試仍然會通過:
用valgrind檢測會得到很長的報告,這裡只看最後的leak summary:
definitely lost和indirectly lost的含義可以看參考資料,這兩個值不為0表示發生了記憶體洩漏。
恢復tear down部分,再次make後用valgrind檢測:
definitely lost和indirectly lost都為0,沒有記憶體洩漏。
說起來valgrind真的非常厲害,比如寫了這種毫無違和感的錯誤**
int main()
真心不一定能看出錯誤,但用valgrind檢測一下,就會在報告裡看到:
提示釋放方法錯誤(mismatched free),應該用delete 。
c 單元測試框架Catch
catch是乙個不錯的單元測試框架,幫助刷leetcode github在此 define catch config main this tells catch to provide a main only do this in one cpp file include catch.hpp incl...
可變引數 VA ARGS 使用和va
1.用來把引數轉換成字串 define p a printf s d n a,a define square x printf the square of x is d.n x x 2.運算子可以用於巨集函式的替換部分。這個運算子把兩個語言符號組合成單個語言符號 3.va args 是乙個可變引數的...
C 異常處理入門 try和catch
目錄 開發程式是一項 燒腦 的工作,程式設計師不但要經過長期的知識學習和思維訓練,還要做到一絲不苟,注意每乙個細節和邊界。即使這樣,也不能防止程式出錯。專家指出,長期作息不規律 用腦過度的危害很大,可能會誘發神經衰弱 失眠等疾病。我就是受害者之一,曾被失眠困擾了好幾年,不但入睡困難,還容易早醒。程式...