前言:
博主目前手頭上管理着幾個設備的跨平臺庫,對外接口大概有七八十個,平常寫測試用例的test文件就有幾十個。趁着最近版本發佈後的空閒時間,對接口庫進行單元測試。與CppUnit類似,CUnit爲C程序員提供了基本的測試功能。
安裝:
博主根據源碼內部工程進行winodw平臺庫編譯時,遇到各種問題,修改了少許源碼後,方能正常運行,已將庫文件上傳
Cunit源碼的下載地址是:https://sourceforge.net/projects/cunit/postdownload
Windows庫文件下載地址: https://download.csdn.net/download/wjb123sw99/12311601
使用文檔:http://cunit.sourceforge.net/doc/index.html
使用:
使用CUnit官網所提供的Demo,讓我們快速熟悉CUnit整體操作。
#include <stdio.h>
#include <string.h>
#include "CUnit/Basic.h"
#include "CUnit/Automated.h"
/* Pointer to the file used by the tests. */
static FILE* temp_file = NULL;
/* The suite initialization function.
* Opens the temporary file used by the tests.
* Returns zero on success, non-zero otherwise.
*/
int init_suite1(void)
{
if (NULL == (temp_file = fopen("temp.txt", "w+"))) {
return -1;
}
else {
return 0;
}
}
/* The suite cleanup function.
* Closes the temporary file used by the tests.
* Returns zero on success, non-zero otherwise.
*/
int clean_suite1(void)
{
if (0 != fclose(temp_file)) {
return -1;
}
else {
temp_file = NULL;
return 0;
}
}
/* Simple test of fprintf().
* Writes test data to the temporary file and checks
* whether the expected number of bytes were written.
*/
void testFPRINTF(void)
{
int i1 = 10;
if (NULL != temp_file) {
CU_ASSERT(0 == fprintf(temp_file, ""));
CU_ASSERT(2 == fprintf(temp_file, "Q\n"));
CU_ASSERT(7 == fprintf(temp_file, "i1 = %d", i1));
}
}
/* Simple test of fread().
* Reads the data previously written by testFPRINTF()
* and checks whether the expected characters are present.
* Must be run after testFPRINTF().
*/
void testFREAD(void)
{
unsigned char buffer[20];
if (NULL != temp_file) {
rewind(temp_file);
CU_ASSERT(9 == fread(buffer, sizeof(unsigned char), 20, temp_file));
CU_ASSERT(0 == strncmp((char *)buffer, "Q\ni1 = 10", 9));
}
}
/* The main() function for setting up and running the tests.
* Returns a CUE_SUCCESS on successful running, another
* CUnit error code on failure.
*/
int main()
{
CU_pSuite pSuite = NULL;
/* initialize the CUnit test registry */
if (CUE_SUCCESS != CU_initialize_registry())
return CU_get_error();
/* add a suite to the registry */
pSuite = CU_add_suite("Suite_1", init_suite1, clean_suite1);
if (NULL == pSuite) {
CU_cleanup_registry();
return CU_get_error();
}
/* add the tests to the suite */
/* NOTE - ORDER IS IMPORTANT - MUST TEST fread() AFTER fprintf() */
if ((NULL == CU_add_test(pSuite, "test of fprintf()", testFPRINTF)) ||
(NULL == CU_add_test(pSuite, "test of fread()", testFREAD)))
{
CU_cleanup_registry();
return CU_get_error();
}
/* Run all tests using the CUnit Basic interface */
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_list_tests_to_file();
CU_automated_run_tests();
CU_cleanup_registry();
return CU_get_error();
}
上述程序運行完後,生成CUnitAutomated-Listing.xml、CUnitAutomated-Results.xml文件,將CUnit-List.dtd、CUnit-List.xsl、CUnit-Run.dtd、CUnit-Run.xsl(這幾個文件在CUnit的源碼包可以找到)和XML文件放到同一級目錄,使用window自帶的IE瀏覽器打開,即可看到單元測試結果。
下面講解下Demo中所使用到的CUnit函數。
函數:
CU_ErrorCode CU_initialize_registry(void);
用戶使用CUnit前,必須運行CU_initialize_registry接口進行測試框架初始化。
錯誤碼:
CUE_SUCCESS | 初始化成功。 |
CUE_NOMEMORY | 內存分配失敗。 |
void CU_cleanup_registry(void);
用戶使用CUnit後,必須運行CU_cleanup_registry接口用於釋放測試框架
CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean);
CU_add_suite函數用於用戶向測試框架註冊一個單元測試;strName【入參】:單元測試的名稱,必須在框架內唯一;pInit【入參】:單元測試初始化程序,類似於構造函數;pClean【入參】:單元測試結束程序,類似於析構函數。CU_InitializeFunc 函數格式定義如下:
typedef int (*CU_InitializeFunc)(void); /**< Signature for suite initialization function. */
如果該註冊函數不需要pInit或者pClean函數,則可以設爲NULL。該函數成功返回單元測試指針CU_pSuite,失敗則返回NULL。
CU_pTest CU_add_test(CU_pSuite pSuite, const char* strName, CU_TestFunc pTestFunc);
CU_add_test函數用於用戶向單元測試中增加一個測試用例,pSuite【入參】:單元測試指針。strName【入參】:測試用例名稱;
pTestFunc【入參】:測試用例函數。CU_TestFunc 函數格式定義如下:
typedef void (*CU_TestFunc)(void); /**< Signature for a testing function in a test case. */
CU_add_test函數成功則返回測試用例指針,失敗則返回NULL。
void CU_basic_set_mode(CU_BasicRunMode mode);
設置基本運行模式,該模式在測試運行期間控制輸出,mode【入參】:可選擇下列參數值
CU_BRM_NORMAL | 打印失敗和運行摘要。 |
CU_BRM_SILENT | 除錯誤消息外,不輸出任何輸出。 |
CU_BRM_VERBOSE | 運行詳細信息的最大輸出。 |
CU_ErrorCode CU_list_tests_to_file(void);
如果用戶想使用Automated模式輸出XML報表,則調用該函數。
void CU_automated_run_tests(void);
使用Automated模式運行測試用例
CU_ErrorCode CU_get_error(void);
由於CUnit部分函數錯誤時,返回NULL。如果用戶想獲取具體錯誤碼,則需要調用CU_get_error函數。
const char* CU_get_error_msg(void);
由於CUnit部分函數錯誤時,返回NULL。如果用戶想獲取具體錯誤信息,則需要調用CU_get_error_msg函數。
斷言:
CUnit提供了一組用於測試邏輯條件的斷言。這些斷言的成功或失敗由框架跟蹤,可以在測試運行完成時查看。
CU_ASSERT(int expression) |
Assert that expression is TRUE (non-zero) |
CU_ASSERT_TRUE(value) |
Assert that value is TRUE (non-zero) |
CU_ASSERT_FALSE(value) |
Assert that value is FALSE (zero) |
CU_ASSERT_EQUAL(actual, expected) |
Assert that actual = = expected |
CU_ASSERT_NOT_EQUAL(actual, expected)) |
Assert that actual != expected |
CU_ASSERT_PTR_EQUAL(actual, expected) |
Assert that pointers actual = = expected |
CU_ASSERT_PTR_NOT_EQUAL(actual, expected) |
Assert that pointers actual != expected |
CU_ASSERT_PTR_NULL(value) |
Assert that pointer value == NULL |
CU_ASSERT_PTR_NOT_NULL(value) |
Assert that pointer value != NULL |
CU_ASSERT_STRING_EQUAL(actual, expected) |
Assert that strings actual and expected are equivalent |
CU_ASSERT_STRING_NOT_EQUAL(actual, expected) |
Assert that strings actual and expected differ |
CU_ASSERT_NSTRING_EQUAL(actual, expected, count) |
Assert that 1st count chars of actual andexpected are the same |
CU_ASSERT_NSTRING_NOT_EQUAL(actual, expected, count) |
Assert that 1st count chars of actual andexpected differ |
CU_ASSERT_DOUBLE_EQUAL(actual, expected, granularity) |
Assert that |actual - expected| <= |granularity| |
CU_ASSERT_DOUBLE_NOT_EQUAL(actual, expected, granularity) |
Assert that |actual - expected| > |granularity| |
CU_PASS(message) |
Register a passing assertion with the specified message. No logical test is performed. |
CU_FAIL(message) |
Register a failed assertion with the specified message. No logical test is performed. |