前言:
博主目前手头上管理着几个设备的跨平台库,对外接口大概有七八十个,平常写测试用例的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. |