CUnit是一个用C语言编写,管理和运行单元测试的轻量级系统。它为C程序员提供了基本的测试功能和灵活的各种用户接口.
CUnit被构建为一个与用户的测试代码链接的静态库。 它使用一个简单的框架来构建测试结构,并为测试常见数据类型提供了一套丰富的断言。 此外,还提供了几个不同的接口来运行测试和报告结果。 这些接口目前包括:
Automated Output to xml file Non-interactive
Basic Flexible programming interface Non-interactive
Console Console interface (ansi C) Interactive
Curses Graphical interface (Unix) Interactive
点击(此处)折叠或打开
- #include <assert.h>
- #include <ctype.h>
- #include <errno.h>
- #include <limits.h>
- #include <string.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <stdio.h>
-
- #include <CUnit/Basic.h>
- #include <CUnit/Console.h>
- #include <CUnit/CUnit.h>
- #include <CUnit/TestDB.h>
- #include <CUnit/Automated.h>
-
- void test_strlen(void)
- {
- char *test_str = "hello world!";
- printf("strlen %d\n", strlen(test_str));
-
- CU_ASSERT(13 == strlen(test_str));
- }
-
- static int init_suite1(void)
- {
- return 0;
- }
-
- static int clean_suite1(void)
- {
- return 0;
- }
-
- int cu_tests(void)
- {
- CU_ErrorCode ret;
- CU_pSuite pSuite = NULL;
-
- ret = CU_initialize_registry();
- if (ret != CUE_SUCCESS) {
- printf("c test initialize failed\n");
- return -1;
- }
-
- printf("c test initialize success\n");
-
- pSuite = CU_add_suite("Suite_1", init_suite1, clean_suite1);
- if (pSuite == NULL) {
- CU_cleanup_registry();
- return CU_get_error();
- }
-
- if (CU_add_test(pSuite, "test of strlen", test_strlen) == NULL) {
- CU_cleanup_registry();
- return CU_get_error();
- }
-
- CU_automated_run_tests();
-
- CU_cleanup_registry();
- printf("clean up all the test case\n");
- return 0;
- }
-
- int main(int argc, char * argv[])
- {
- cu_tests();
- return 0;
- }
CUnit是平台无关的框架与各种用户接口的组合。 核心框架为管理测试注册表,套件和测试用例提供了基本支持。 用户接口便于与框架交互以运行测试和查看结果。
CUnit像传统的单元测试框架一样组织:
Test Registry | ------------------------------ | | Suite '1' . . . . Suite 'N' | | --------------- --------------- | | | | Test '11' ... Test '1M' Test 'N1' ... Test 'NM'
单独的测试用例被打包到套件中,这些套件已在活动测试注册表中注册。 套件可以具有设置和拆卸功能,在运行套件测试之前和之后自动调用它们。 注册表中的所有套件/测试可以使用单个函数调用来运行,或者可以运行选定的套件或测试。
用法:
使用CUnit框架的典型步骤顺序是:
编写用于测试的函数(如果需要,还可以使用suite init / cleanup)。
初始化测试注册表 - CU_initialize_registry()
将套件添加到测试注册表 - CU_add_suite()
将测试添加到套件 - CU_add_test()
使用适当的界面运行测试,例如CU_console_run_tests
清理测试注册表 - CU_cleanup_registry
编写CUnit测试用例:
测试功能
CUnit“测试”是一个C函数,其命名为:
void test_func(void)
除了不应修改CUnit框架(例如,添加套件或测试,修改测试注册表或启动测试运行)之外,对测试功能的内容没有限制。 测试函数可能会调用其他函数(也可能不会修改框架)。 注册测试会导致测试用例运行时运行它的功能。
返回最多2个整数的例程的示例测试函数可能如下所示:
int maxi(int i1,int i2)
{
return(i1> i2)? i1:i2;
}
void test_maxi(void)
{
CU_ASSERT(maxi(0,2)== 2);
CU_ASSERT(maxi(0,-2)== 0);
CU_ASSERT(maxi(2,2)== 2);
}
CUnit断言:
CUnit提供了一组测试逻辑条件的断言。 这些断言的成功或失败由框架跟踪,并且可以在测试运行完成时查看。
每个断言测试一个逻辑条件,如果条件评估为FALSE,则失败。 失败后,除非用户选择断言的'xxx_FATAL'版本,否则测试功能将继续。 在那种情况下,测试功能被中止并立即返回。 致命的版本断言应谨慎使用! 一旦FATAL断言失败,测试功能就没有机会自行清理。 但是,普通套件清理功能不受影响。
还有一些特殊的“断言”用于在没有进行逻辑测试的情况下注册框架的合格或不合格。 这些对于测试控制流或不需要逻辑测试的其他条件很有用:
void test_longjmp(void) { jmp_buf buf; int i; i = setjmp(buf); if (i == 0) { run_other_func(); CU_PASS("run_other_func() succeeded."); } else CU_FAIL("run_other_func() issued longjmp."); }
断言列表
CU_ASSERT(int expression) CU_ASSERT_FATAL(int expression) CU_TEST(int expression) CU_TEST_FATAL(int expression) |
Assert that expression is TRUE (non-zero) |
CU_ASSERT_TRUE(value) CU_ASSERT_TRUE_FATAL(value) |
Assert that value is TRUE (non-zero) |
CU_ASSERT_FALSE(value) CU_ASSERT_FALSE_FATAL(value) |
Assert that value is FALSE (zero) |
CU_ASSERT_EQUAL(actual, expected) CU_ASSERT_EQUAL_FATAL(actual, expected) |
Assert that actual = = expected
|
CU_ASSERT_NOT_EQUAL(actual, expected)) CU_ASSERT_NOT_EQUAL_FATAL(actual, expected) |
Assert that actual != expected
|
CU_ASSERT_PTR_EQUAL(actual, expected) CU_ASSERT_PTR_EQUAL_FATAL(actual, expected) |
Assert that pointers actual = = expected
|
CU_ASSERT_PTR_NOT_EQUAL(actual, expected) CU_ASSERT_PTR_NOT_EQUAL_FATAL(actual, expected) |
Assert that pointers actual != expected
|
CU_ASSERT_PTR_NULL(value) CU_ASSERT_PTR_NULL_FATAL(value) |
Assert that pointer value == NULL |
CU_ASSERT_PTR_NOT_NULL(value) CU_ASSERT_PTR_NOT_NULL_FATAL(value) |
Assert that pointer value != NULL |
CU_ASSERT_STRING_EQUAL(actual, expected) CU_ASSERT_STRING_EQUAL_FATAL(actual, expected) |
Assert that strings actual and expected are equivalent |
CU_ASSERT_STRING_NOT_EQUAL(actual, expected) CU_ASSERT_STRING_NOT_EQUAL_FATAL(actual, expected) |
Assert that strings actual and expected differ |
CU_ASSERT_NSTRING_EQUAL(actual, expected, count) CU_ASSERT_NSTRING_EQUAL_FATAL(actual, expected, count) |
Assert that 1st count chars of actual and expected are the same |
CU_ASSERT_NSTRING_NOT_EQUAL(actual, expected, count) CU_ASSERT_NSTRING_NOT_EQUAL_FATAL(actual, expected, count) |
Assert that 1st count chars of actual and expected differ |
CU_ASSERT_DOUBLE_EQUAL(actual, expected, granularity) CU_ASSERT_DOUBLE_EQUAL_FATAL(actual, expected, granularity) |
Assert that |actual - expected| <= |granularity| Math library must be linked in for this assertion.
|
CU_ASSERT_DOUBLE_NOT_EQUAL(actual, expected, granularity) CU_ASSERT_DOUBLE_NOT_EQUAL_FATAL(actual, expected, granularity) |
Assert that |actual - expected| > |granularity| Math library must be linked in for this assertion.
|
CU_PASS(message) |
Register a passing assertion with the specified message. No logical test is performed. |
CU_FAIL(message) CU_FAIL_FATAL(message) |
Register a failed assertion with the specified message. No logical test is performed. |
测试注册表
#include <CUnit/TestDB.h> (included automatically by <CUnit/CUnit.h>)
typedef struct CU_TestRegistry typedef CU_TestRegistry* CU_pTestRegistry CU_ErrorCode CU_initialize_registry(void) void CU_cleanup_registry(void) CU_pTestRegistry CU_get_registry(void) CU_pTestRegistry CU_set_registry(CU_pTestRegistry pTestRegistry) CU_pTestRegistry CU_create_new_registry(void) void CU_destroy_existing_registry(CU_pTestRegistry* ppRegistry)
内部结构
测试注册表是套件和相关测试的存储库。 CUnit维护一个活动的测试注册表,在用户添加一个套件或测试时更新。 这个活动注册表中的套件是当用户选择运行所有测试时运行的套件。
CUnit测试注册表是在中声明的数据结构CU_TestRegistry。 它包括存储在注册表中的套件和测试总数的字段,以及指向注册套件链接列表头部的指针。
typedef struct CU_TestRegistry { unsigned int uiNumberOfSuites; unsigned int uiNumberOfTests; CU_pSuite pSuite; } CU_TestRegistry; typedef CU_TestRegistry* CU_pTestRegistry;
用户通常只需在使用前初始化注册表,然后进行清理。 但是,在必要时提供其他功能来操作注册表。
初始化
CU_ErrorCode CU_initialize_registry(void)
活动的CUnit测试注册表必须在使用前初始化。 在调用任何其他CUnit函数之前,用户应该调用CU_initialize_registry()。 不这样做可能会导致崩溃。
返回错误状态码:
CUE_SUCCESS |
initialization was successful. |
CUE_NOMEMORY |
memory allocation failed. |
清除:
void CU_cleanup_registry(void)
当测试完成后,用户应该调用这个函数来清理和释放框架使用的内存。 这应该是所调用的最后一个CUnit函数(除了使用CU_initialize_registry()或CU_set_registry())还原测试注册表。
未能调用CU_cleanup_registry()将导致内存泄漏。 如果不创建错误条件,可能会多次调用它。 请注意,该函数将销毁注册表中的所有套件(和相关测试)。 清理注册表后,指向已注册的套件和测试的指针不应被解除引用。
调用CU_cleanup_registry()只会影响CUnit框架维护的内部CU_TestRegistry。 销毁用户拥有的任何其他测试注册表是用户的责任。 这可以通过调用CU_destroy_existing_registry()来明确地完成,或者通过使用CU_set_registry()使注册表处于活动状态并再次调用CU_cleanup_registry()来隐式地完成。
管理测试和套件
为了让CUnit运行一个测试,它必须被添加到一个在测试注册表中注册的测试集合(套件)。
#include <CUnit/TestDB.h> (included automatically by <CUnit/CUnit.h>)
typedef struct CU_Suite typedef CU_Suite* CU_pSuite typedef struct CU_Test typedef CU_Test* CU_pTest typedef void (*CU_TestFunc)(void) typedef int (*CU_InitializeFunc)(void) typedef int (*CU_CleanupFunc)(void) CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean); CU_pTest CU_add_test(CU_pSuite pSuite, const char* strName, CU_TestFunc pTestFunc); typedef struct CU_TestInfo typedef struct CU_SuiteInfo CU_ErrorCode CU_register_suites(CU_SuiteInfo suite_info[]); CU_ErrorCode CU_register_nsuites(int suite_count, ...);
将套件添加到注册表中
CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean)
创建具有指定名称,初始化函数和清理函数的新测试集合(套件)。 新套件已在测试注册表中注册(并由其拥有),因此注册表必须在添加任何套件之前进行初始化。 当前的实现不支持创建独立于测试注册表的套件。
该套件的名称在注册表中的所有套件中必须是唯一的。 初始化和清理函数是可选的,并且作为指针传递给函数,以在运行套件中包含的测试之前和之后被调用。 这允许套件设置和拆卸临时设备以支持运行测试。 这些函数没有参数,如果成功完成则返回零(否则为非零)。 如果套件不需要这些函数中的一个或两个,则将NULL传递给CU_add_suite()。
返回指向新套件的指针,这是向套件添加测试所需的。 如果发生错误,则返回NULL,并将框架错误代码设置为以下值之一:
CUE_SUCCESS |
suite creation was successful. |
CUE_NOREGISTRY |
the registry has not been initialized. |
CUE_NO_SUITENAME |
strName was NULL. |
CUE_DUP_SUITE |
the suite's name was not unique. |
CUE_NOMEMORY |
memory allocation failed. |
添加测试函数到套件:
CU_pTest CU_add_test(CU_pSuite pSuite, const char* strName, CU_TestFunc pTestFunc)
创建一个具有指定名称和测试函数的新测试,并将其注册到指定的套件。 该套件必须已经使用CU_add_suite()创建。 当前的实现不支持创建独立于注册套件的测试。
测试的名称在添加到单个套件的所有测试中必须是唯一的。 测试函数不能为NULL,并且指向运行测试时要调用的函数。 测试函数既没有参数也没有返回值。
返回指向新测试的指针。 如果在创建测试期间发生错误,则返回NULL,并将框架错误代码设置为以下值之一:
CUE_SUCCESS |
suite creation was successful. |
CUE_NOSUITE |
the specified suite was NULL or invalid. |
CUE_NO_TESTNAME |
strName was NULL. |
CUE_NO_TEST |
pTestFunc was NULL or invalid. |
CUE_DUP_TEST |
the test's name was not unique. |
CUE_NOMEMORY |
memory allocation failed. |
管理测试函数的快捷方法:
#define CU_ADD_TEST(suite, test) (CU_add_test(suite, #test, (CU_TestFunc)test))
该宏根据测试函数名称自动生成一个唯一的测试名称,并将其添加到指定的套件中。 返回值应该由用户检查以验证成功。
CU_ErrorCode CU_register_suites(CU_SuiteInfo suite_info[])
CU_ErrorCode CU_register_nsuites(int suite_count, ...)
对于包含许多测试和套件的大型测试结构,管理测试/套件关联和注册非常繁琐且容易出错。 CUnit提供特殊的注册系统来帮助管理套件和测试。 它的主要好处是集中套件和相关测试的注册,并尽量减少用户需要编写的错误检查代码的数量。
测试用例首先被分组到CU_TestInfo实例的数组中(定义在中):
CU_TestInfo test_array1[] = { { "testname1", test_func1 }, { "testname2", test_func2 }, { "testname3", test_func3 }, CU_TEST_INFO_NULL, };
每个数组元素包含单个测试用例的(唯一)名称和测试函数。 数组必须以一个保存NULL值的元素结尾,宏CU_TEST_INFO_NULL便于定义。 包含在单个CU_TestInfo数组中的测试用例构成了将用单个测试套件注册的测试集。
套件信息然后在一个或多个CU_SuiteInfo实例数组中定义(在中定义):
CU_SuiteInfo suites[] = { { "suitename1", suite1_init-func, suite1_cleanup_func, test_array1 }, { "suitename2", suite2_init-func, suite2_cleanup_func, test_array2 }, CU_SUITE_INFO_NULL, };
每个数组元素都包含单个套件的(唯一)名称,套件初始化函数,套件清理函数和CU_TestInfo数组。 像往常一样,如果给定的套件不需要它,NULL可以用于初始化或清理函数。 该数组必须以一个全NULL元素结尾,可以使用宏CU_SUITE_INFO_NULL。
所有在CU_SuiteInfo数组中定义的套件都可以在一个语句中注册:
CU_ErrorCode error = CU_register_suites(suites);
如果在任何套件或测试的注册期间发生错误,则返回错误代码。 错误代码与普通套件注册和测试添加操作返回的错误代码相同。 函数CU_register_nsuites()用于用户希望在一个语句中注册多个CU_SuiteInfo数组的情况:
CU_ErrorCode error = CU_register_nsuites(2, suites1, suites2);
该函数接受可变数量的CU_SuiteInfo数组。 第一个参数表示传递数组的实际数量。
运行测试用例:
#include <CUnit/Automated.h>
void CU_automated_run_tests(void) CU_ErrorCode CU_list_tests_to_file(void) void CU_set_output_filename(const char* szFilenameRoot)
#include <CUnit/Basic.h>
typedef enum CU_BasicRunMode CU_ErrorCode CU_basic_run_tests(void) CU_ErrorCode CU_basic_run_suite(CU_pSuite pSuite) CU_ErrorCode CU_basic_run_test(CU_pSuite pSuite, CU_pTest pTest) void CU_basic_set_mode(CU_BasicRunMode mode) CU_BasicRunMode CU_basic_get_mode(void) void CU_basic_show_failures(CU_pFailureRecord pFailure)
#include <CUnit/Console.h>
void CU_console_run_tests(void)
#include <CUnit/CUCurses.h>
void CU_curses_run_tests(void)
#include <CUnit/TestRun.h> (included automatically by <CUnit/CUnit.h>)
unsigned int CU_get_number_of_suites_run(void) unsigned int CU_get_number_of_suites_failed(void) unsigned int CU_get_number_of_tests_run(void) unsigned int CU_get_number_of_tests_failed(void) unsigned int CU_get_number_of_asserts(void) unsigned int CU_get_number_of_successes(void) unsigned int CU_get_number_of_failures(void) typedef struct CU_RunSummary typedef CU_Runsummary* CU_pRunSummary const CU_pRunSummary CU_get_run_summary(void) typedef struct CU_FailureRecord typedef CU_FailureRecord* CU_pFailureRecord const CU_pFailureRecord CU_get_failure_list(void) unsigned int CU_get_number_of_failure_records(void)
CUnit支持在所有注册套件中运行所有测试,但也可以运行单个测试或套件。 在每次运行期间,框架会跟踪运行,传递和失败的套件,测试和断言的数量。 请注意,每次启动测试运行时都会清除结果(即使失败)。
虽然CUnit提供了用于运行套件和测试的原始函数,但大多数用户都希望使用其中一个简化的用户界面。 这些接口处理与框架交互的细节,并为用户提供测试细节和结果的输出。
CUnit库中包含以下接口:
Interface Platform Description
Automated all non-interactive with output to xml files
Basic all non-interactive with optional output to stdout
Console all interactive console mode under user control
Curses Linux/Unix interactive curses mode under user control
自动模式
自动化界面是非交互式的。 客户端启动测试运行,并将结果输出到XML文件。 注册测试和套件的列表也可以报告给XML文件。
以下功能组成了自动化接口API:
void CU_automated_run_tests(void)
运行所有注册套件中的所有测试。 测试结果输出到名为ROOT-Results.xml的文件。 文件名ROOT可以使用CU_set_output_filename()来设置,否则使用默认的CUnitAutomated-Results.xml。 请注意,如果在每次运行之前未设置distict filename ROOT,结果文件将被覆盖。
结果文件由文档类型定义文件(CUnit-Run.dtd)和XSL样式表(CUnit-Run.xsl)支持。 这些在源和安装树的Share子目录中提供。
CU_ErrorCode CU_list_tests_to_file(void)
列出要注册的套件和相关测试。 列表文件名为ROOT-Listing.xml。 文件名ROOT可以使用CU_set_output_filename()来设置,否则使用默认的CUnitAutomated。 请注意,如果在每次运行之前未设置distict filename ROOT,则列表文件将被覆盖。
列表文件由文档类型定义文件(CUnit-List.dtd)和XSL样式表(CUnit-List.xsl)支持。 这些在源和安装树的Share子目录中提供。
另请注意,清单文件不是由CU_automated_run_tests()自动生成的。 客户代码必须在需要时明确请求列表。
void CU_set_output_filename(const char* szFilenameRoot)
设置结果和列表文件的输出文件名。 szFilenameRoot分别用于附加-Results.xml和-Listing.xml来构造文件名。
错误处理:
#include <CUnit/CUError.h> (included automatically by <CUnit/CUnit.h>)
typedef enum CU_ErrorCode CU_ErrorCode CU_get_error(void); const char* CU_get_error_msg(void); typedef enum CU_ErrorAction void CU_set_error_action(CU_ErrorAction action); CU_ErrorAction CU_get_error_action(void);
大多数CUnit函数都会设置一个指示框架错误状态的错误代码。 一些函数返回代码,而其他函数只是设置代码并返回其他值。 提供了两个函数来检查框架错误状态:
CU_ErrorCode CU_get_error(void)
const char* CU_get_error_msg(void)
第一个返回错误代码本身,而第二个返回描述错误状态的消息。 错误代码是中定义的CU_ErrorCode类型的枚举。 定义了以下错误代码值:
Error Value |
Description |
CUE_SUCCESS |
No error condition. |
CUE_NOMEMORY |
Memory allocation failed. |
CUE_NOREGISTRY |
Test registry not initialized. |
CUE_REGISTRY_EXISTS |
Attempt to CU_set_registry() without CU_cleanup_registry(). |
CUE_NOSUITE |
A required CU_pSuite pointer was NULL. |
CUE_NO_SUITENAME |
Required CU_Suite name not provided. |
CUE_SINIT_FAILED |
Suite initialization failed. |
CUE_SCLEAN_FAILED |
Suite cleanup failed. |
CUE_DUP_SUITE |
Duplicate suite name not allowed. |
CUE_NOTEST |
A required CU_pTest pointer was NULL. |
CUE_NO_TESTNAME |
Required CU_Test name not provided. |
CUE_DUP_TEST |
Duplicate test case name not allowed. |
CUE_TEST_NOT_IN_SUITE |
Test is not registered in the specified suite. |
CUE_FOPEN_FAILED |
An error occurred opening a file. |
CUE_FCLOSE_FAILED |
An error occurred closing a file. |
CUE_BAD_FILENAME |
A bad filename was requested (NULL, empty, nonexistent, etc.). |
CUE_WRITE_ERROR |
An error occurred during a write to a file. |
遇到错误情况时的默认行为是要设置错误代码并继续执行。 客户可能有时候喜欢测试运行,以防止出现框架错误,甚至不希望测试应用程序退出。 这种行为可以由用户设置,为此提供了以下功能:
void CU_set_error_action(CU_ErrorAction action)
CU_ErrorAction CU_get_error_action(void)
错误操作代码是中定义的CU_ErrorAction类型的枚举。 定义了以下错误操作代码:
Error Value |
Description |
CUEA_IGNORE |
Runs should be continued when an error condition occurs (default) |
CUEA_FAIL |
Runs should be stopped when an error condition occurs |
CUEA_ABORT |
The application should exit() when an error conditions occurs |
本文转载至:http://blog.chinaunix.net/uid-25242461-id-5784456.html