單元測試框架的原理和實現(模仿google test)
阿新 • • 發佈:2020-07-15
2020/7/14
學習內容:
-
單元測試框架的編寫與實現,單元測試框架屬於測試的一部分,驗證程式的某一部分邏輯是否正確。
-
模仿google test模組的方式,在檔案中加入多個TEST函式,然後呼叫RUN_ALL_TESTS函式就可以執行所有的TEST函式,並且返回結果;
-
TEST函式其實並不是真正意義上的一個函式,而是通過巨集定義實現的一個檔案頭。因為多個TEST函式存在於同一個檔案中肯定是不符合c語言的語法的。
通過以下程式碼定義TEST
#define TEST(a, b) void a_##_b() //定義了一個函式頭 #define EXPECT(a, comp ,b) {\ if (!((a) comp (b))) { \ test_func_flag = 1; \ //用於標記測試是否出錯,全域性變數 expect_printf(__FILE__, __LINE__, "(" #a ") " #comp " (" #b ")"); \ } \ } #define EXPECT_EQ(a, b) EXPECT(a, ==, b); //這裡使用了一個技巧 #define EXPECT_NE(a, b) EXPECT(a, !=, b); //但是這樣我們不知道有幾個測試用例,如何執行測試用例 //使用attribute註冊函式使函式先於main函式執行 //將TEST(a, b)改為如下 #define TEST(a, b) \ void a##_##b();\ //這一句是宣告這個測試函式,不然在註冊函式時會出現未宣告 __attribute__((constructor)) \ //先於main函式執行 void add_##a##_##b() { \ add_func(a##_##b, #a "." #b); \ }\ void a##_##b() //原來的函式頭放在了這裡 //接下來實現一些介面函式和結構 struct Func_Data { void (*func)(); const char *func_name; } func_arr[100]; //真正的工程中是不可以用一個固定大小的陣列的 int func_cnt; void add_func(void (*func)(), const char *func_name) { func_arr[func_cnt].func = func; func_arr[func_cnt].func_name = func_name; func_cnt++; return; //禮貌性的返回 } int test_func_flag; void expect_printf(const char *file, int line_on, const char *msg) { printf(YELLOW" %s:%d : Failure\n", file, line_on); printf(YELLOW" Expected: %s\n"NONE, msg); return; } int RUN_ALL_TEST() { printf(GREEN"[==========]"NONE" Running %d tests\n", func_cnt); for (int i = 0; i < func_cnt; i++) { printf(GREEN"[ RUN ] %s\n", func_arr[i].func_name); test_func_flag = 0; int b = clock(); func_arr[i].func(); int e = clock(); if (test_func_flag) { printf(RED"[ FAILED ]\n"NONE); } else { printf(GREEN"[ OK ]\n"NONE); } printf(" %s (%s ms)\n", func[i].func_name, 1000 * (e - b) / CLOCK_PER_SEC); } return 0; } //將測試函式封裝在testcasen.h中 #ifdef DEBUG #include "testcase.h" #endif //... #ifdef DEBUG return RUN_ALL_TESTS(); #else return 0; #endif //makefile 的編寫 release: debug: -DDEBUG