当前位置: 首页 > 工具软件 > CUnit > 使用案例 >

CUnit

裴英锐
2023-12-01


CUnit用户手册

1介绍使用CUnit进行单元测试

1.1描述

CUnit是一个通过C语言编写的用于编写、管理和执行单元测试用例的测试系统。它往往被编成库的形式(静态库或动态库)提供给用户测试代码进行链接。
CUnit使用一个简单的框架构建测试结构,并提供了一组丰富的断言来测试常见的数据类型。此外,还提供了几个不同的接口用来运行测试和报告结果。这些接口包括代码控制测试和报告的自动化接口,以及允许用户动态运行测试和查看结果的交互式界面接口。
下面的头文件中为典型的用户声明了有用的数据类型和功能接口:
Header File Description
#include <CUnit/CUnit.h> ASSERT(断言)宏在测试案例中使用,包括其他框架的头文件。
#include <CUnit/CUError.h> 错误处理函数和数据类型。被CUnit.h文件自动包含。
#include <CUnit/TestDB.h> 数据类型的定义和测试套、测试用例的注册功能接口。
被CUnit.h文件自动包含。
#include <CUnit/TestRun.h> 数据类型的定义和运行测试、检索结果的功能接口。
被CUnit.h文件自动包含。
#include <CUnit/Automated.h> 自动XML输出接口。
#include <CUnit/Basic.h> 一个非交互的输出到标准输出(stdout)的基本接口。
#include <CUnit/Console.h> 交互式控制台界面。
#include <CUnit/CUCurses.h> 交互式控制台接口(* nix平台)。
#include <CUnit/Win.h> Windows界面(尚未实施)。

1.2结构

CUnit是独立于平台的框架具有各种用户接口的组合。这样一个核心框架提供了如测试注册表,测试套和测试用例管理的基本功能支持。用户通过用户界面的框架进行执行测试并查看结果的交互操作。
CUnit的组织结构类似于一个常规的单元测试框架:
Test Registry
|
------------------------------
| |
Suite ‘1’ . . . . Suite ‘N’
| |
--------------- ---------------
| | | |
Test ‘11’ … Test ‘1M’ Test ‘N1’ … Test ‘NM’
独立的测试用例被封装到已经在测试注册表注册与激活的测试套中。每个测试套都对应有自己的构造和析构函数,这两个函数会在测试套运行前后被自动调用执行。在注册表中的所有测试套/测试用例可以通过调用一个函数来执行,或都有选择的运行对应的测试套或测试用例。

1.3通常用法

以下是使用CUnit框架的基本的步骤:

  1. 写待测函数(必要时进行测试套初始化或清除工作)。
    2.初始化的测试注册表 - CU_initialize_registry()
  2. 将测试套添加到测试注册表 - CU_add_suite()
  3. 往测试套里添加测试用例- CU_add_test(测试)
  4. 调用合适的接口函数执行测试用例,例如CU_console_run_tests
  5. 清除测试注册表- CU_cleanup_registry

1.4 CUnit第2版中的API变更

在Cunit中所有公共函数名现在都以 “CU_”作为前缀。这有利于避免与用户代码中的函数名发生冲突。需要注意的是早期版本的CUnit使用的是不同的函数名且没有这个前缀的。旧的API的名已被弃用,但仍支持。要使用旧的名称,用户代码必须使用USE_DEPRECATED_CUNIT_NAMES的宏定义进行编译。那些过时的API函数在文档中有相应部分的描述。

2 编写CUnit测试用例

2.1测试函数

一般一个CUnit的测试用例以“test”作为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);
}

2.2 CUnit断言

CUnit提供了一组用于测试逻辑条件的断言。这些成功或失败的断言被框架进行跟踪记录,当测试执行结束后可以对记录的结果进行查看。
每个断言测试一个单一的逻辑条件,如果条件的计算结果为CU_FALSE则失败。除非用户选择“xxx_FATAL的版本的断言,否则在失败时测试函数仍会继续执行。在这种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.");

}

被已注册的测试函数调用的其他函数可自由使用CUnit断言。这些断言将被计算到调用它们的函数中。它们也可以使用FATAL版本的失败断言,这将中止原来的测试函数和调用它的整个调用链。
CUnit对断言定义如下:
#include <CUnit/CUnit.h>
CU_ASSERT(int expression)
CU_ASSERT_FATAL(int expression)
CU_TEST(int expression)
CU_TEST_FATAL(int expression) 断言表达expression是CU_TRUE(非零)
CU_ASSERT_TRUE(value)
CU_ASSERT_TRUE_FATAL(value) 断言值value是CU_TRUE(非零)

CU_ASSERT_FALSE(value)
CU_ASSERT_FALSE_FATAL(value) 断言值value是CU_FALSE(零)

CU_ASSERT_EQUAL(actual, expected)
CU_ASSERT_EQUAL_FATAL(actual, expected) 断言 actual (实际)= = expected(预期)
CU_ASSERT_NOT_EQUAL(actual, expected))
CU_ASSERT_NOT_EQUAL_FATAL(actual, expected) 断言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) 断言的实际和预期的字符串是等价的

CU_ASSERT_STRING_NOT_EQUAL(actual, expected)
CU_ASSERT_STRING_NOT_EQUAL_FATAL(actual, expected) 断言字符串的实际和预期不同

CU_ASSERT_NSTRING_EQUAL(actual, expected, count)
CU_ASSERT_NSTRING_EQUAL_FATAL(actual, expected, count) 断言的实际和预期的第1次计数字符是相同的

CU_ASSERT_NSTRING_NOT_EQUAL(actual, expected, count)
CU_ASSERT_NSTRING_NOT_EQUAL_FATAL(actual, expected, count) 断言第1次计数字符的实际和预期的不同

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) 注册一个指定的通过断言的消息。不可进行逻辑测试。

CU_FAIL(message)
CU_FAIL_FATAL(message) 注册一个指定的失败断言的消息。不可进行逻辑测试。

2.3不建议使用的V1版本的断言

下面的断言是不建议在第2版使用。要使用这些断言,用户代码必须由USE_DEPRECATED_CUNIT_NAMES编译定义。需要注意的是在第1版本中他们的行为是相同的(发生故障时,发出“return”语句)。
#include <CUnit/CUnit.h>
不建议使用的宏名 等价的新宏名
ASSERT CU_ASSERT_FATAL
ASSERT_TRUE CU_ASSERT_TRUE_FATAL
ASSERT_FALSE CU_ASSERT_FALSE_FATAL
ASSERT_EQUAL CU_ASSERT_EQUAL_FATAL
ASSERT_NOT_EQUAL CU_ASSERT_NOT_EQUAL_FATAL
ASSERT_PTR_EQUAL CU_ASSERT_PTR_EQUAL_FATAL
ASSERT_PTR_NOT_EQUAL CU_ASSERT_PTR_NOT_EQUAL_FATAL
ASSERT_PTR_NULL CU_ASSERT_PTR_NULL_FATAL
ASSERT_PTR_NOT_NULL CU_ASSERT_PTR_NOT_NULL_FATAL
ASSERT_STRING_EQUAL CU_ASSERT_STRING_EQUAL_FATAL
ASSERT_STRING_NOT_EQUAL CU_ASSERT_STRING_NOT_EQUAL_FATAL
ASSERT_NSTRING_EQUAL CU_ASSERT_NSTRING_EQUAL_FATAL
ASSERT_NSTRING_NOT_EQUAL CU_ASSERT_NSTRING_NOT_EQUAL_FATAL
ASSERT_DOUBLE_EQUAL CU_ASSERT_DOUBLE_EQUAL_FATAL
ASSERT_DOUBLE_NOT_EQUAL CU_ASSERT_DOUBLE_NOT_EQUAL_FATAL

3测试注册表

3.1 简介

#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_BOOL CU_registry_initialized(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)

3.2注册表内部结构

测试注册表是测试套和相关测试用例的储存系统。CUnit维护这样一个被激活的注册表,当用户增加了一个测试套或测试用例时这个注册表被更新。在这种激活的注册表中,当用户选择运行所有测试用例时,测试套作为执行的一个完整单元。
CUnit测试注册表是在<CUnit/TestDB.h>文件中声明的一个数据结构CU_TestRegistry。它包括存储在注册表中的测试套和测试用例的总数,以及一个指向已注册的测试套链表的头指针。
typedef struct CU_TestRegistry
{
unsigned int uiNumberOfSuites;
unsigned int uiNumberOfTests;
CU_pSuite pSuite;
} CU_TestRegistry;

typedef CU_TestRegistry* CU_pTestRegistry;

用户通常只需要在使用前初始化注册表,使用后对其清理。然而,必要时其他的一些功能函数也可以对提供的注册表进行必要操纵。

3.3注册表初始化

CU_ErrorCode CU_initialize_registry(void)
激活的CUnit测试注册表使用之前必须初始化。用户在调用任何其他CUnit功能函数之前应先调用CU_initialize_registry的()。如果不这样做,可能会导致系统崩溃。
返回一个错误状态码:
CUE_SUCCESS 初始化成功。
CUE_NOMEMORY 内存申请失败。

CU_BOOL CU_registry_initialized(void)
此功能可用于检查是否已初始化注册表。如果是分布在多个文件,当需要确保注册表是已经可以进行测试用例的注册时可以调用这个函数进行判断。

3.4 注册表清除

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()。

3.5其他注册表函数

其他注册表函数主要用于内部和测试目的。但是,一般的用户可以了解并使用它们,至少应该知道。
其中包括:

CU_pTestRegistry CU_get_registry(void)
返回一个指向激活的测试注册表的指针。注册表是一个CU_TestRegistry数据类型的变量。直接对内部测试注册表进行操作是不建议的——应该使用API函数进行操作。该框架保持了注册表的所有权,所以当调用CU_cleanup_registry()或CU_initialize_registry()函数后,调用该函数返回的指针将失效。

CU_pTestRegistry CU_set_registry(CU_pTestRegistry pTestRegistry)
替换用指定激活的注册表,返回之前的注册表的指针。摧毁旧的注册表是调用者的职责,这可以通过对返回的指针显式地通过调用CU_destroy_existing_registry()实现。另外,可以先使用CU_set_registry()使注册表激活和再调用CU_cleanup_registry()隐式地销毁。应当注意的是,不要显式地去破坏一个被激活的注册表,这可能导致多次释放相同一个内存块并很可能引起崩溃。

CU_pTestRegistry CU_create_new_registry(void)
创建一个新的注册表并返回一个指向它的指针。新的注册表不包含任何的测试套或测试用例。通过之前机制描述销毁新的注册表是调用者的责任。

void CU_destroy_existing_registry(CU_pTestRegistry* ppRegistry)
销毁指定的测试注册表包括所有测试套、测试用例,并释放其所有的内存。这个函数不应该对被设置为激活状态的测试注册表调用(如CU_pTestRegistry指针检索的使用CU_get_registry())。当CU_cleanup_registry()被调用时,这将导致多次释放相同的内存。ppRegistry可能不为NULL,但指针内容可以为空。在这种情况下,该函数无效。需要注意的是在返回时* ppRegistry将被设置为NULL。

3.6 不建议使用的V1的数据类型和函数

下面的数据类型和函数不建议在第2版使用。要使用这些过时的名称,用户代码必须用USE_DEPRECATED_CUnit_NAMES进行编译定义。
#include <CUnit/TestDB.h> (included automatically by CUnit/CUnit.h>).
不建议使用的函数名 等价的新函数名
_TestRegistry CU_TestRegistry
_TestRegistry.uiNumberOfGroups
PTestRegistry->uiNumberOfGroups CU_TestRegistry.uiNumberOfSuites
CU_pTestRegistry->uiNumberOfSuites
_TestRegistry.pGroup
PTestRegistry->pGroup CU_TestRegistry.pSuite
CU_pTestRegistry->pSuite
PTestRegistry CU_pTestRegistry
initialize_registry() CU_initialize_registry()
cleanup_registry() CU_cleanup_registry()
get_registry() CU_get_registry()
set_registry() CU_set_registry()

4测试及测试套管理

为了让CUnit运行一个测试用例,必须将其添加到由测试注册表注册的测试集(套)中。

4.1简介

#include <CUnit/TestDB.h> (included automatically by <CUnit/CUnit.h>)

typedef struct CU_Suite
{
char* pName; /< Suite name. */
CU_pTest pTest; /
< Pointer to the 1st test in the suite. */
CU_InitializeFunc pInitializeFunc; /< Pointer to the suite initialization function. */
CU_CleanupFunc pCleanupFunc; /
< Pointer to the suite cleanup function. */

unsigned int uiNumberOfTests; /< Number of tests in the suite. /
struct CU_Suite
pNext; /
< Pointer to the next suite in linked list. /
struct CU_Suite
pPrev; /**< Pointer to the previous suite in linked list. */

} CU_Suite;
typedef CU_Suite* CU_pSuite; /**< Pointer to a CUnit suite. */

typedef struct CU_Test
{
char* pName; /< Test name. */
CU_TestFunc pTestFunc; /
< Pointer to the test function. /
jmp_buf
pJumpBuf; /**< Jump buffer for setjmp/longjmp test abort mechanism. */

struct CU_Test* pNext; /< Pointer to the next test in linked list. /
struct CU_Test
pPrev; /
< Pointer to the previous test in linked list. */

} CU_Test;
typedef CU_Test* CU_pTest; /**< Pointer to a CUnit test case. */

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_SuiteInfo {
char *pName; /< Suite name. */
CU_InitializeFunc pInitFunc; /
< Suite initialization function. */
CU_CleanupFunc pCleanupFunc; /< Suite cleanup function */
CU_TestInfo *pTests; /
< Test case array - must be NULL terminated. /
} CU_SuiteInfo;
typedef CU_SuiteInfo
CU_pSuiteInfo; /**< Pointer to CU_SuiteInfo type. */

typedef struct CU_TestInfo {
char *pName; /< Test name. */
CU_TestFunc pTestFunc; /
< Test function. /
} CU_TestInfo;
typedef CU_TestInfo
CU_pTestInfo; /**< Pointer to CU_TestInfo type. */

CU_ErrorCode CU_register_suites(CU_SuiteInfo suite_info[]);
CU_ErrorCode CU_register_nsuites(int suite_count, …);

4.2往注册表中添加测试套

CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean)
创建一个新的测试集(套),具有指定的名称、构造函数和析构函数功能。新的测试套通过测试注册表(拥有者)注册的,所以注册表必须进行初始化,然后再添加任何测试套。目前CUnit的实现并不支持创建独立于测试注册表的测试套。该函数不能在执行测试时调用。
在注册表中所有测试套的名称必须是唯一的。初始化和清理功能函数是可选的,传送运行测试套之前和之后调用的函数指针。这使得该测试套可以临时建立和拆除固定装置,以支持运行测试用例。这些函数没有参数,如果他们执行成功应返回零(否则返回非零值)。如果一测试套并不需要这些功能中的一个或两个则对应传递给CU_add_suite()的参数设为NULL。
该函数返回一个指向到新测试套的指针,当往该测试套添加测试用例时将会用到该指针。如果发生错误,则返回NULL,框架错误代码被设置为下列之一:
CUE_SUCCESS 测试套创建成功。
CUE_NOREGISTRY 测试注册表仍未初始化。
CUE_NO_SUITENAME 测试套名(strName)为空NULL
CUE_DUP_SUITE 测试套名不唯一。
CUE_NOMEMORY 内存申请失败。

4.3 往测试套中添加测试用例

CU_pTest CU_add_test(CU_pSuite pSuite, const char* strName, CU_TestFunc pTestFunc)
创建一个新的具有指定名称和测试功能的测试用例,并注册到指定的测试套中。所指定的测试套必须是已经调用CU_add_suite()创建好了的。CUnit目前的实现并不支持创建独立于测试套的测试用例。该函数不能在执行测试时调用。
添加到同一个测试套的所有测试用例的名称必须是唯一的。测试函数不能为空,须指向一个运行测试时被调用函数。测试函数既没有参数也没有返回值。
该函数返回一个指针新的测试用例的指针。如果创建测试过程中发生错误则返回NULL,框架错误代码被设置为下列之一:
CUE_SUCCESS 测试用例创建成功。
CUE_NOREGISTRY 测试注册表仍未初始化。
CUE_NOSUITE 指定的测试套无效
CUE_NO_TESTNAME 测试套名(strName)为空NULL
CUE_NO_TEST 测试函数指针无效
CUE_DUP_TEST 测试用例名不唯一
CUE_NOMEMORY 内存申请失败。

4.4管理测试用例的快捷方法

#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(在<CUnit/TestDB.h>中有定义)的矩阵实例中:
CU_TestInfo test_array1[] = {
{ “testname1”, test_func1 },
{ “testname2”, test_func2 },
{ “testname3”, test_func3 },
CU_TEST_INFO_NULL,
};
矩阵中每个数组元素包含一个测试用例的的名称(唯一)和测试函数。该数组的结束元素必须为NULL,可以用由宏CU_TEST_INFO_NULL定义的NULL值。包含在一个CU_TestInfo矩阵实例下的所用测试用例被封装成了一个测试集,这个测试集将被注册到同一个测试套中。

测试套信息可分布在一个或多个CU_SuiteInfo(在<CUnit/TestDB.h>中有定义)矩阵实例中定义:
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矩阵数目。第一个参加指明了实际被传递进来的矩阵的个数。

4.5 测试套和测试用例的激活

CU_ErrorCode CU_set_suite_active(CU_pSuite pSuite, CU_BOOL fNewActive)
CU_ErrorCode CU_set_test_active(CU_pTest pTest, CU_BOOL fNewActive)
这两个函数可用于禁用或激活个别的测试套和测试用例。一个测试套或测试用例如果为非激活状态则在测试执行时不会被执行。所有的测试套和测试用例在创建时默认激活状态。可以分别通过pSuite->fActive 和 pTest->fActive 标志来识别测试套和测试用例的当前激活状态。如果为激活状态该标志将CU_TRUE否则为CU_FALSE。这使客户能动态选择要执行的部分测试用例集。请注意,禁用了一个测试套或测试用例然后又指定执行它是一个框架错误操作。这些函数如果执行成功返回CUE_SUCCESS,如果相应的测试套(或测试用例)为空的则返回 CUE_NOSUITE (或CUE_NOTEST)。

4.6 修改测试套和测试用例的其它属性

通常,测试套和测试用例的属性集在创建时设置。在某些情况下,客户希望可以通过操纵这些属性动态地修改测试结构。以下功能是提供用于此目的,其可以用于替代直接设置的数据结构的成员的值的方式。这些函数如果执行成功返回CUE_SUCCESS,如果相应的测试套(或测试用例)为空的则返回 CUE_NOSUITE (或CUE_NOTEST)。

CU_ErrorCode CU_set_suite_name(CU_pSuite pSuite, const char *strNewName)
CU_ErrorCode CU_set_test_name(CU_pTest pTest, const char *strNewName)
这两个函数用于变更所注册的测试套和测试用例的名称。可以分别用于 pSuite->pName and pTest->pName 的数据结构成员。如果测试套或测试用例为空,将分别返回 CUE_NOSUITE 或CUE_NOTEST。如果设置的名称为空,将分别返回 CUE_NO_SUITENAME 或CUE_NO_TESTNAME。

CU_ErrorCode CU_set_suite_initfunc(CU_pSuite pSuite, CU_InitializeFunc pNewInit)
CU_ErrorCode CU_set_suite_cleanupfunc(CU_pSuite pSuite, CU_CleanupFunc pNewClean)
这两个函数用例改变所注册的测试套的初始化函数和清理函数。可以分别用于p pSuite->pInitializeFunc and pSuite->pCleanupFunc 数据结构的成员。如果测试套为空则返回CUE_NOSUITE。

CU_ErrorCode CU_set_test_func(CU_pTest pTest, CU_TestFunc pNewFunc)
这个函数用于变化已注册的测试用例的测试函数。可用于pTest->pTestFunc 数据结构成员。如果测试函数为空则返回CUE_NOTEST。

4.7 查找私有的测试套和测试用例

在大多数情况下,客户将要通过调用 CU_add_suite() 和 CU_add_test() 返回的指针来参考已经注册的测试套和测试用例。有时,客户可能需要能够检索参考测试套和测试用例。下面的函数是提供协助客户及当客户有一些关于实体的信息(名称或其它注册信息)。在对测试套或测试用例没有什么已知信息的情况下,客户端将需要迭代的内部数据结构来列举测试套和测试用例。这是不直接支持客户端的API。

CU_pSuite CU_get_suite(const char* strName)
CU_pSuite CU_get_suite_at_pos(unsigned int pos)
unsigned int CU_get_suite_pos(CU_pSuite pSuite)
unsigned int CU_get_suite_pos_by_name(const char* strName)
这些函数帮助在激活的测试注册表中查找已注册的测试套。前2个函数可以通过名称或位置的查找测试套,如果无法找到则返回null。位置是从1开始索引的在范围[ 1…CU_get_registry()->uiNumberOfSuites]。这可能注册有重名的测试套,在这种情况下,只能查找第一次检索对应名字的测试套。第二个2函数,帮助客户确定注册的测试套的位置。如果无法找到的测试套则直接返回NULL。此外,如果注册表未初始化,这些函数会设置CUnit的错误状态为CUE_NOREGISTRY。同理,当传入的名字为NULL时设置错误状态为 CUE_NO_SUITENAME ,当找不到对应的测试套时设置为CUE_NOSUITE。

CU_pTest CU_get_test(CU_pSuite pSuite, const char *strName)
CU_pTest CU_get_test_at_pos(CU_pSuite pSuite, unsigned int pos)
unsigned int CU_get_test_pos(CU_pSuite pSuite, CU_pTest pTest)
unsigned int CU_get_test_pos_by_name(CU_pSuite pSuite, const char *strName)
这些函数帮助在指定的测试套中查找测试用例。前2个函数可以通过名称或位置的查找测试套,如果无法找到则返回null。位置是从1开始索引的在范围[ 1…pSuite->uiNumberOfSuites]。这可能注册有重名的测试用例,在这种情况下,只能查找第一次检索对应名字的测试用例。第二个2函数帮助客户识别的测试用例在测试套中的位置。如果找不到测试用例则返回0。此外,如果注册表未初始化,这些函数会设置CUnit的错误状态为CUE_NOREGISTRY,如果测试套为NULL则设置为CUE_NOSUITE。同理,当传入的名字为NULL时设置错误状态为 CUE_NO_TESTNAME ,当找不到对应的测试套时设置为CUE_NOTEST。

4.8已过时V1数据的类型和函数

下面的数据类型和函数不建议在第2版使用。要使用这些过时的名称,用户代码必须用USE_DEPRECATED_CUNIT_NAMES进行编译定义。
#include <CUnit/TestDB.h> (included automatically by CUnit/CUnit.h>).
不建议使用的函数名 等价的新函数名
TestFunc CU_TestFunc
InitializeFunc CU_InitializeFunc
CleanupFunc CU_CleanupFunc
_TestCase CU_Test
PTestCase CU_pTest
_TestGroup CU_Suite
PTestGroup CU_pSuite
add_test_group() CU_add_suite()
add_test_case() CU_add_test()
ADD_TEST_TO_GROUP() CU_ADD_TEST()
test_case_t CU_TestInfo
test_group_t CU_SuiteInfo
test_suite_t no equivalent - use CU_SuiteInfo
TEST_CASE_NULL CU_TEST_INFO_NULL
TEST_GROUP_NULL CU_SUITE_INFO_NULL
test_group_register CU_register_suites()
test_suite_register no equivalent - use CU_register_suites()

5执行测试

5.1 简介

#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)
<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)

5.2 CUnit执行测试

CUnit支持运行注册在所有测试套中的所有测试用例,同时也可以单独地运行测试套或测试用例。在每次运行时,测试框架会跟踪记录运行的测试套、测试用例和运行通过或失败的断言数。注意,这些结果会在每次测试运行开始(即使它失败)时被清零。
Cunit提供原函数运行测试套和测试用例,大多数用户将要使用到其中一个简化的用户界面。这些接口处理与框架的间的相互关系的细节工作并为用户提供输出测试的细节和结果。
下列接口包括在CUnit库:
Interface Platform Description
Automated all 非交互式输出到xml文件
Basic all 非交互式的可选输出到标准输出(stdout)。
Console all 在用户控制下的交互式控制台方式。
Curses Linux/Unix 在用户控制下的互动curses(诅咒)模式
如果这些接口仍满足需要,客户端也可以使用在<CUnit/TestRun.h>文件中定义框架的原始API。请参阅例如,如何与原始API直接交互的源代码的各种接口。

5.3自动模式

自动化接口是非交互式的。客户端启动试运行,并输出结果是一个XML文件。注册测试和测试套的列表同时也可以打印报告到XML文件中。
下面的功能包括自动化接口(API):

void CU_automated_run_tests(void)
运行所有已注册的(且为激活的)测试套的所有测试用例。测试结果输出到一个文件名为ROOT-Results.xml.的文件中。可以使用CU_set_output_filename()设置文件名ROOT,否则使用默认文件名为CUnitAutomated-Results.xml。需要注意的是,如果一个局部的ROOT文件名在每次运行前没有设置,结果文件将被覆盖。
结果文件支持文件类型定义的文件(CUnit Run.dtd)和XSL样式表(CUnit Run.xsl)。这些在源码和安装路径的共享子目录中有提供。

CU_ErrorCode CU_list_tests_to_file(void)
列举已注册的测试套和相关的测试用例到文件。该列表文件被命名为ROOT-Listing.xml。可以使用CU_set_output_filename()设置文件名ROOT,否则使用默认CUnitAutomated-Results.xml。需要注意的是,如果一个局部的ROOT文件名在每次运行前没有设置,结果文件将被覆盖。
结果文件支持文件类型定义的文件(CUnit-Run.dtd)和XSL样式表(CUnit-Run.xsl)。这些在源码和安装路径的共享子目录中有提供。
还要注意的是列表文件不是由调用CU_automated_run_tests()自动生成的。当用户需要列表信息时,客户端代码必须调用该接口作出明确的要求。

void CU_set_output_filename(const char* szFilenameRoot)
设置输出的测试结果及列表文件的文件名。szFilenameRoot被用来构造文件名,分别通过附加-Results.xml和-Listing.xml。

5.4基本模式

基本界面也是非交互式的,结果输出到标准输出(stdout)。此接口支持运行单独的套房或测试,并允许客户端代码来控制每次运行过程中显示的输出类型。此接口为希望简化访问CUnit的API的客户提供了最大的灵活性。
提供以下公共函数:

CU_ErrorCode CU_basic_run_tests(void)
运行所有已注册的测试套中的所有测试用例。返回试运行期间发生的第一个错误代码。输出类型由当前的运行模式控制,该模式可以使用CU_basic_set_mode()进行设置。

CU_ErrorCode CU_basic_run_suite(CU_pSuite pSuite)
运行指定的单一测试套中的所有测试用例。返回试运行期间发生的第一个错误代码。输出类型由当前的运行模式控制,该模式可以使用CU_basic_set_mode()进行设置。

CU_ErrorCode CU_basic_run_test(CU_pSuite pSuite, CU_pTest pTest)
运行指定的测试套中的单一测试用例。返回试运行期间发生的第一个错误代码。输出类型由当前的运行模式控制,该模式可以使用CU_basic_set_mode()进行设置。

void CU_basic_set_mode(CU_BasicRunMode mode)
设置的基本运行模式,该模式在测试运行期间控制输出。模块选择如下:
CU_BRM_NORMAL 打印故障和运行结果。
CU_BRM_SILENT 除错误消息外不打印输出.
CU_BRM_VERBOSE 最大程度地输出运行的详细信息。

CU_BasicRunMode CU_basic_get_mode(void)
检索当前的基本运行模式的代码。

void CU_basic_show_failures(CU_pFailureRecord pFailure)
将所有失败汇总打印到stdout。不依赖于运行模式。

5.5交互式控制台模式

控制台界面是交互式的。所有的客户端需要做的是启动控制台会话,并且用户以交互方式运行控制测试。这些操作包括选择和运行注册的测试套和测试用例,并查看测试结果。要启动控制台会话,使用
void CU_console_run_tests(void)

5.6交互式curses模式

curses界面是交互式的。所有的客户端需要做的是启动的curses会话和用户交互方式运行控制测试。这些操作包括选择和运行注册的测试套和测试用例,并查看测试结果。使用这个接口需要连接到应用程序中的ncurses库。要启动curses会话,使用
void CU_curses_run_tests(void)

5.7获得测试结果

以上的一些接口都会显示测试运行的结果,但有时客户端的代码可能需要直接访问结果。这些结果包括各种运行计数,以及作为的失败记录保持的故障的详细信息的链接列表。注意:测试结果是覆盖每次一个新的测试运行开始时,或者当注册表被初始化或清理的时候。
访问测试结果的函数如下:

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)

这些函数报告在上一次运行时的测试套数测试用例数和运行的或失败的断言数目。如果一个测试套的初始化或清理函数返回非NULL,则该测试套被认为是失败。一个测试用例中任何一个断言失败则认为这个测试用例是失败。最后的3个函数返回的是对应情况的断言数目。
要检索的注册的测试套和测试用例的总数,可以分别使用CU_get_registry() - > uiNumberOfSuites和CU_get_registry() - > uiNumberOfTests实现。

const CU_pRunSummary CU_get_run_summary(void)
一次检索所有测试计数结果。返回值是一个指向包含计数结果值的存储结构的指针。此数据类型的定义在<CUnit/TestRun.h>(自动包含于<CUnit/CUnit.h>):
typedef struct CU_RunSummary
{
unsigned int nSuitesRun;
unsigned int nSuitesFailed;
unsigned int nTestsRun;
unsigned int nTestsFailed;
unsigned int nAsserts;
unsigned int nAssertsFailed;
unsigned int nFailureRecords;
} CU_RunSummary;
typedef CU_Runsummary* CU_pRunSummary;
返回的指针的结构变量为框架所拥有,因此用户不应该释放它或以其他方式改变它。请注意,一旦启动另一个测试运行指针可能会失效。

const CU_pFailureRecord CU_get_failure_list(void)
获取一个记录在最后一次测试发生任何失败的链表(NULL表示无失败)。返回值的数据类型在<CUnit/TestRun.h>文件(自动包含于<CUnit/CUnit.h>文件中)中有定义。每个失败记录包含的信息包括失败位置和失败性质:
typedef struct CU_FailureRecord
{
unsigned int uiLineNumber;
char* strFileName;
char* strCondition;
CU_pTest pTest;
CU_pSuite pSuite;

struct CU_FailureRecord* pNext;  
struct CU_FailureRecord* pPrev;  

} CU_FailureRecord;

 typedef CU_FailureRecord*  CU_pFailureRecord;

返回的指针的结构变量为框架所拥有,因此用户不应该释放它或以其他方式改变它。请注意,一旦启动另一个测试运行指针可能会失效。
unsigned int CU_get_number_of_failure_records(void)
检索由CU_get_failure_list()返回的失败链接列表中CU_FailureRecords结点的个数。请注意,这个数值可能比失败的断言数量多,因为测试套的初始化和清除的失败也计算在内。

5.8已过时V1数据的类型和功能

下面的数据类型和函数不建议在第2版使用。要使用这些过时的名称,用户代码必须用USE_DEPRECATED_CUNIT_NAMES进行编译定义。
不建议使用的函数名 等价的新函数名
automated_run_tests() CU_automated_run_tests() plus
CU_list_tests_to_file()
set_output_filename() CU_set_output_filename()
console_run_tests() CU_console_run_tests()
curses_run_tests() CU_curses_run_tests()

6错误处理

6.1简介

#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);

6.2 CUnit错误处理

CUnit的大多数函数设置错误代码来表示的框架错误状态。有些函数返回错误代码,而其他人函数只是设置错误代码,并返回一些其它的数值。两个函数提供测试框架错误状态:
CU_ErrorCode CU_get_error(void)
const char* CU_get_error_msg(void)
第一个函数返回的错误代码,而第二个函数返回一条描述的错误状态的消息。错误代码是在<CUnit/CUError.h>文件中定义的一个CU_ErrorCode枚举类型。
下面的错误代码值定义如下:
Error Value Description
CUE_SUCCESS 无错误状态.
CUE_NOMEMORY 内存申请失败
CUE_NOREGISTRY 测试注册表未初始化
CUE_REGISTRY_EXISTS 在没有CU_cleanup_registry()前尝试CU_set_registry()。
CUE_NOSUITE 一个必需的CU_pSuite指针为NULL。
CUE_NO_SUITENAME 未提供所需CU_Suite名。
CUE_SINIT_FAILED 测试套初始化失败
CUE_SCLEAN_FAILED 测试套清除失败
CUE_DUP_SUITE 不允许重复测试套名称。
CUE_NOTEST 一个必需的CU_pTest指针为NULL。
CUE_NO_TESTNAME 未提供所需的CU_Test名。
CUE_DUP_TEST 不允许重复的测试用例名称。
CUE_TEST_NOT_IN_SUITE 测试用例未注册在指定的测试套。
CUE_FOPEN_FAILED 打开一个文件时发生错误。
CUE_FCLOSE_FAILED 关闭一个文件时发生错误。
CUE_BAD_FILENAME 要求一个坏的文件名(NULL,空的,不存在等)。
CUE_WRITE_ERROR 在写入到一个文件过程中出现错误。

6.3框架错误时的行为

遇到一个错误条件时的缺省行为是针对错误代码设置并继续执行。很多时候有可能是客户想要运行的测试用例停在了一个框架错误的时候,甚至测试应用程序的退出的时候。这种行为可以由用户设置,提供以下函数:
void CU_set_error_action(CU_ErrorAction action)
CU_ErrorAction CU_get_error_action(void)
错误的动作代码是一个定义在<CUnit/CUError.h>文件中的CU_ErrorAction枚举类型。下面的错误操作代码的定义如下:
Error Value Description
CUEA_IGNORE 运行时发生错误情况,应继续运行(默认)
CUEA_FAIL 运行发生错误情况时,应停止
CUEA_ABORT 运行出现错误条件进应用程序应该退出

6.4已过时V1变量和函数

下面的数据类型和函数不建议在第2版使用。要使用这些过时的名称,用户代码必须用USE_DEPRECATED_CUNIT_NAMES进行编译定义。
Deprecated Name Equivalent New Name
get_error() CU_get_error_msg()
error_code None. Use CU_get_error()

相关阅读

相关文章

相关问答