1. 程式人生 > >C語言單元測試框架unit的使用

C語言單元測試框架unit的使用

針對C語言的測試框架相比其他語言要少一些,本文簡單介紹一下Cunit框架的基本使用方法,權當備忘吧。Cunit的組織框架如下圖所示:
在這裡插入圖片描述
將單個測試用例打包到一個suite中,這些suite在Registry中註冊。registry中的所有suite/tests可以使用單個函式呼叫執行,也可以執行選定的套件或測試。下面看一個例子

首先我們新建檔案,寫一個待測試函式,這裡以一個字串轉換數字函式為例,這是我們的第一版實現

// convert.c
// 版本1
int 
str_to_int(char* s)
{
    int sum = 0;
    char *p = s;
    while (*p != 0) {
        sum = sum * 10 + *p -'0';
        p++;
    }
    return sum;
}

顯然這個函式是有很多問題的,我們寫一個測試函式來測試它。

void 
TEST_str_to_int()
{
    int ans;
    char *p;
    char *ps[] = { "123", "-123", "0", "siahideib",  "2147483648", "2147483647", "-1-2", "            -2147483647", "  -2147483648aaaa"};
    int real[] = {123,    -123,   0,   0,            0,            2147483647,   -1,     -2147483647,               -2147483648};

    int i = 0;
    for (i = 0; i < sizeof(real)/sizeof(real[0]); i++) {
        ans = str_to_int(ps[i]);
        CU_ASSERT_EQUAL(ans,real[i]);
    }
}

測試函式和被測函式寫好之後,我們就可以定義一個registry 和一個suite,在suite中新增被測函式,並在registry中註冊。

addTestModule()
{
    CU_pSuite pSuite = NULL;
    // 新增suite
    pSuite = CU_add_suite("str_to_int測試模組", suite_success_init, suite_success_clean);  
    if (pSuite == NULL) {
        return -1;
    }
    // 在suite中新增被測函式
    if (NULL == CU_add_test(pSuite,"str_to_int",TEST_str_to_int)) {
		return -1;
	}
    return 0;
}

Cunit提供了三種模式檢視單元測試結果,分別是控制檯模式,基本模式和報表模式

void 
run_test()
{
    if (CU_initialize_registry()) {
        printf("error");
        return ;
    } 
    assert(NULL != CU_get_registry());
    assert(!CU_is_test_running()); 
    if (0 != addTestModule()) {
		CU_cleanup_registry();
		return ;
	}
    
    // 報表模式
    // 設定輸出檔名稱
    CU_set_output_filename("str_to_int_test_report");
    CU_list_tests_to_file();
    CU_automated_run_tests();

    // 基本模式
    // CU_basic_set_mode(CU_BRM_VERBOSE);
    // CU_basic_run_tests();      
    // 控制檯模式
    // CU_console_run_tests();       
    // CU_console_run_tests();
    CU_cleanup_registry();
}

最後寫一個main函式來呼叫測試函式

#include<stdio.h>
#include "test.h"
int 
main()
{
    run_test();
    return 0;
}

編譯執行

gcc -g convert.c main.c test.c -lcunit
./a.out

執行完成後,在當前目錄下可以看到生成了兩個xml檔案,這兩個檔案就是得到的測試結果。

str_to_int_test_report-Listing.xml
str_to_int_test_report-Results.xml

不過這兩個檔案不能直接開啟,需要把cunit安裝目錄下的另外四個檔案複製過來。如果預設安裝的話,這四個檔案一般在/usr/local/share/CUnit目錄下

CUnit-List.dtd
CUnit-List.xsl  
CUnit-Run.dtd  
CUnit-Run.xsl

把這6個檔案拷貝到同一路徑下,就可以通過IE或者Edge瀏覽器檢視輸出結果。
在這裡插入圖片描述
可以看到,9個測試用例有3個沒有通過。改進一下被測函式

// convert.c
// 版本2
int 
str_to_int(char* s)
{
    int     sign = 1;
    char    *p = s;
    long    sum = 0;
    
    // 指標判空
    if (!s) {
        return 0;
    }
    
    // 排除空格
    while (*p == ' ')
        p++;
    //控制符號
    if (*p == '-') {
        sign = -1;
        p++;
    } else if (*p == '+') {
        sign = 1;
        p++;
    }

    while (*p >= '0' && *p <= '9') {
        // 左移比乘法效率高,注意優先順序
        sum = (sum << 3) + (sum << 1) + *p -'0';
        // 處理溢位
        if ((sum > INT_MAX && sign == 1) || sum > (long)INT_MAX + 1 && sign == -1) {
            sum = 0;
            break;
        }
        p++;
    }
    return (int)sum * sign;
}

重新編譯,執行,看一下測試結果,這一次9個case全部通過
在這裡插入圖片描述