Glib 对 C 函数进行单元测试
1. Glib 單元測試框架
Glib 為單元測試提供了一套完整的測試框架,每個測試運行包括以下幾個部分
- 測試數據結構
- 測試 setup 與 teardown 函數
- 測試函數
2. 單元測試數據結構
在一組測試中使用的元素稱為一個 fixture,Glib 要求每個 fixture 都是一個結構,所以我們需要聲明一個結構體,包含我們測試數據或是對象。
/** fixture for Glib test */ typedef struct Matrix2dTest {Matrix2d mat; ///< test objectdouble TOL; ///< maximum error } Matrix2dTest;如上代碼中定義了我們測試所需結構體 Matrix2dTest,結構體中元素 mat 即為后面進行測試的對象(結構體)。
3. 測試環境構建
在每個測試函數運行前,可能都需要進行一系列初始化和后處理操作。Glib 運行時將這兩個過程函數作為參數傳給測試函數,如此一來,每個測試函數都可以生成一個新的程序來運行,并且互不影響。
添加測試函數的語句是
g_test_add("/MatUtils/Test_inverseMatrix2d", // test labelMatrix2dTest, // test structureNULL, // input user dataSetup_Matrix2dTest, // setup functionTest_inverseMatrix2d, // test functionTeardown_Matrix2dTest); // teardown function其中,Matrix2dTest 和 NULL 為測試函數輸入參數,Test_inverseMatrix2d 為測試函數,Setup_Matrix2dTest 和 Teardown_Matrix2dTest 為測試初始化和后處理函數。
在調用測試函數時候,Glib 通過 fork 系統調用生成新的線程來測試失敗。運行 g_test_run() 語句即可運行所有測試,具體執行命令可參見第5節。
4. 單元測試函數
由于測試框架是確定的,因此單元測試函數參數也是固定的。在上面測試中,我們添加測試函數名為 Test_inverseMatrix2d,函數完整定義為
static void Test_inverseMatrix2d(Matrix2dTest* mattest, const void* test_data) {Matrix2d mat1;mallocMatrix2d(3, 3, &mat1);copyMatrix2d(mattest->mat, &mat1);inverseMatrix2d(mat1);Matrix2d mat2;mallocMatrix2d(3, 3, &mat2);multiplyMatrix2d(mattest->mat, mat1, 1.0, 0.0, mat2);g_assert(fabs(mat2.ets[0][0] - 1.0) < mattest->TOL);g_assert(fabs(mat2.ets[1][1] - 1.0) < mattest->TOL);g_assert(fabs(mat2.ets[2][2] - 1.0) < mattest->TOL);freeMatrix2d(mat1);freeMatrix2d(mat2); }可以看到,由于函數只有文件內測試用,因此聲明為 static 函數。函數有兩個參數,第一個為 mattest 類型指針,第二個為傳入用戶數據,由于我們不需要其他數據,因此調用時傳入 NULL。
這個測試主要用來測試矩陣求逆過程,計算完成后將逆矩陣與矩陣相乘,看結果是否為單元矩陣。最后的判斷采用如下語句
g_assert(fabs(mat2.ets[0][0] - 1.0) < mattest->TOL);g_assert(fabs(mat2.ets[1][1] - 1.0) < mattest->TOL);g_assert(fabs(mat2.ets[2][2] - 1.0) < mattest->TOL);5. 完整測試函數
#include <stdio.h> #include <math.h> #include "MatUtils.h" #include <glib.h>/** fixture for Glib test */ typedef struct Matrix2dTest {Matrix2d mat; ///< test objectdouble TOL; ///< maximum error } Matrix2dTest;static void Setup_Matrix2dTest(Matrix2dTest* mattest, const void* test_data) {mallocMatrix2d(3, 3, &(mattest->mat));double vt[] = {3.0, -1.0, -1.0, 4.0, -2.0, -1.0, -3.0, 2.0, 1.0,};mattest->TOL = 1e-6;setMatrix2dFromArray(vt, mattest->mat); }static void Teardown_Matrix2dTest(Matrix2dTest* mattest, const void* test_data) {freeMatrix2d(mattest->mat); }static void Test_inverseMatrix2d(Matrix2dTest* mattest, const void* test_data) {Matrix2d mat1;mallocMatrix2d(3, 3, &mat1);copyMatrix2d(mattest->mat, &mat1);inverseMatrix2d(mat1);Matrix2d mat2;mallocMatrix2d(3, 3, &mat2);multiplyMatrix2d(mattest->mat, mat1, 1.0, 0.0, mat2);g_assert(fabs(mat2.ets[0][0] - 1.0) < mattest->TOL);g_assert(fabs(mat2.ets[1][1] - 1.0) < mattest->TOL);g_assert(fabs(mat2.ets[2][2] - 1.0) < mattest->TOL);freeMatrix2d(mat1);freeMatrix2d(mat2); }int main(int argc, char** argv) {g_test_init(&argc, &argv, NULL);g_test_add("/MatUtils/Test_inverseMatrix2d", // test labelMatrix2dTest, // test structureNULL, // input user dataSetup_Matrix2dTest, // setup functionTest_inverseMatrix2d, // test functionTeardown_Matrix2dTest); // teardown functionreturn g_test_run(); }編譯時由于需要鏈接 Glib 函數庫所以需要添加一些附加命令。這里我采用的是 cmake 軟件編譯,在工程根目錄的 CMakeLists.txt 中直接添加如下命令添加 Glib 頭文件和庫文件目錄,
find_package(PkgConfig REQUIRED) pkg_check_modules(GLIB REQUIRED glib-2.0>=2.23) include_directories(${GLIB_INCLUDE_DIRS}) link_directories(${GLIB_LIBRARY_DIRS})在測試函數所在的文件夾內 CMakeLists.txt 中,則添加如下命令編譯測試函數
target_link_libraries(MatUtilsTest matutils ${GLIB_LIBRARIES})如此便可對測試函數進行正確的編譯和鏈接了。
獲得可執行的測試函數后,用過命令
gtester -k -o=test.xml ./MatUtilsTest生成測試結果文件 test.xml,再利用語句 gtester-report 命令即可將 XML 文件轉化為 html 文件,并用留瀏覽器打開。
gtester-report test.xml > test.html但是不知什么原因,在我的 Macbook 筆記本上出現錯誤
? build gtester-report test.xml > test.html Traceback (most recent call last):File "/usr/local/bin/gtester-report", line 490, in <module>main()File "/usr/local/bin/gtester-report", line 484, in mainHTMLReportWriter(rr.get_info(), rr.binary_list()).printout()File "/usr/local/bin/gtester-report", line 348, in printoutself.handle_info ()File "/usr/local/bin/gtester-report", line 242, in handle_infoself.oprint ('<h3>Package: %(package)s, version: %(version)s</h3>\n' % self.info) KeyError: 'package'通過搜索我發現是 xml 文件缺少內容所致 Running gtester-report on gtester output raises KeyError。打開 xml 文件,在 <gtester> 字段內添加
<info> <package>PACKAGENAME</package> <version>VERSION</version> <revision>REVISION</revision>語句,聲明軟件名和軟件版本。如此便可得到可視化的測試結果,如圖所示:
參考文獻
理解 GLib 的單元測試框架
https://segmentfault.com/a/1190000003996312
Ben Klemens. C程序設計新思維[M]. 人民郵電出版社, 2015.
轉載于:https://www.cnblogs.com/li12242/p/8419527.html
總結
以上是生活随笔為你收集整理的Glib 对 C 函数进行单元测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简单显示分配器的实现
- 下一篇: 2.7随笔