CUnit使用简介

2009-06-13 16:17 | 分类:CUnit, 原创 | 标签:, | 作者:Aaron | 733 views

一、介绍

继Junit CppUnit的成功后, c语言环境下也出现了开发源码的白盒测试用例CUnit。CUnit以静态库的形式提供给用户使用,用户编写程序的时候直接链接此静态库就可以了。它提供了一个简单的单元测试框架,并且为常用的数据类型提供了丰富的断言语句支持。

二、结构框架

在CUnit的主页上可以看到对他结构的简单描述

                   Test Registry
                        |
         ——————————
         |                            |
      Suite ‘1′      . . . .       Suite ‘N’
         |                            |
   —————             —————
   |             |             |             |
Test ‘11′ … Test ‘1M’     Test ‘N1′ … Test ‘NM’

CUnit的测试是单线程启动,只能注册一个测试用例Test Registry,测试用例下可以注册多个测试套件Suite,每个套件下可以注册多个测试函数Test,每个测试函数里又可以写多个断言ASSERT。

 

三、测试模式

下面是四种测试模式:
1 Automated Output to xml file Non-interactive
2 Basic Flexible programming interface Non-interactive
3 Console Console interface (ansi C) Interactive
4 Curses Graphical interface (Unix) Interact

注意1,2是没有交互功能的,4是Unix下的。

Windows下的Basic模式灵活性比较大一点,比如你可以选择如下运行模式:
CU_BRM_NORMAL    /**< 正常模式 - 打印错误和运行总结 [默认] */
CU_BRM_SILENT      /**< 安静模式 - 只打印框架错误信息 */
CU_BRM_VERBOSE  /**< 冗余模式 - 输出详细的运行结果 */

还可以指定遇见错误时的动作:
CUEA_IGNORE        /**< 当出现错误时继续往下运行 */
CUEA_FAIL             /**< 当有错误出现时停止(stop) */
CUEA_ABORT         /**< 当错误出现时应用程序终止(exit) */

第一种Automated运行以后会自动生成一个xml文件,通过dtd和xsl文件的辅助可以在浏览器中显示出测试结果。

第三种Console个人认为目前的功能还不是很强大,主要功能就是可以分别执行测试套件suite程序,但是操作起来十分的不方便。

四、测试基本流程

使用CUnit进行测试的基本流程如下所示:
1.书写待测试的函数(如果有必要,需要写suite的init/cleanup函数)
2.初始化Test Registry - CU_initialize_registry()
3.把测试套件(Test Suites)加入到Test Registry - CU_add_suite()
4.加入测试用例(Test Case)到测试套件当中 - CU_add_test()
5.使用适当的接口来运行测试测试程序,例如 CU_console_run_tests()
6.清除Test Registry - CU_cleanup_registry()

五、测试框架的安装

没有CUnit源码去http://sourceforge.net/projects/cunit/去下一份,笔者使用的是CUnit-2.1-0,安装十分的方便,Unix下只需要configure, make, make install就行了,Windows下也有相应的VC工程目录,这里就不再獒述了,需要注意的是,源代码里的Example使用了废弃的CUnit函数命名,所以编译的时候需要加一个USE_DEPRECATED_CUNIT_NAMES预定义。

六、具体使用

/* test.c */
int maxi(int i, int j)
{
    return i > j ? i : j;
}
/* testcase.c */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <CUnit/CUnit.h>
 
/**
 * 待测试的函数
 */
extern int maxi(int i, int j);
 
/**
 * 测试函数
 * 必须满足签名式 void func(void)
*/
void testIQJ(void)
{
    CU_ASSERT_EQUAL(maxi(1,1),1);
    CU_ASSERT_EQUAL(maxi(0,-0),0);
}
void testIGJ(void)
{
    CU_ASSERT_EQUAL(maxi(2,1),2);
    CU_ASSERT_EQUAL(maxi(0,-1),0);
    CU_ASSERT_EQUAL(maxi(-1,-2),-1);
}
void testILJ(void)
{
    CU_ASSERT_EQUAL(maxi(1,2),2);
    CU_ASSERT_EQUAL(maxi(-1,0),0);
    CU_ASSERT_EQUAL(maxi(-2,-1),-1);
}
 
/**
 * 测试函数信息的结构体
 * 当然也可以使用 CU_add_test()
 * 注意必须以 CU_TEST_INFO_NULL 结尾
 */
CU_TestInfo testcases[] =
{
    {"Testing i equals j:", testIQJ},
    {"Testing i greater than j:", testIGJ},
    {"Testing i less than j:", testILJ},
    CU_TEST_INFO_NULL
};
 
/**
 * 测试套件初始化函数,对测试函数中的资源进行初始化
 * 返回0为成功,如果返回失败则此套件下的测试均不运行
 */
int suite_init(void)
{
    return 0;
}
 
/**
 * 测试套件销毁函数,对测试函数中的资源进行销毁
 * 返回0为成功,如果返回失败不影响测试,只会报测试套件运行错误
 */
int suite_clean(void)
{
    return 0;
}
 
/**
* 测试套件信息的结构体
* 当然也可以使用 CU_add_suite()
* 注意必须以 CU_SUITE_INFO_NULL 结尾
* 如不需要初始化或者最终化函数则可以传NULL
*/
CU_SuiteInfo suites[] =
{
    {"Testing the function maxi:", suite_init, suite_clean, testcases},
    CU_SUITE_INFO_NULL
};
 
/**
 * 增加到Registry中
 */
void AddTests(void)
{
    assert(NULL != CU_get_registry());
    assert(!CU_is_test_running());
 
    if(CUE_SUCCESS != CU_register_suites(suites)){
        fprintf(stderr, "Register suites failed - %s ", CU_get_error_msg());
        exit(EXIT_FAILURE);
    }
}
/* main.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <CUnit/Basic.h>
#include <CUnit/Automated.h>
#include <CUnit/Console.h>
 
extern void AddTests(void);
 
int main(int argc, char* argv[])
{
    /* 为Basic模式使用 */
    CU_BasicRunMode mode = CU_BRM_VERBOSE;
    CU_ErrorAction error_action = CUEA_IGNORE;
    int i;
 
    setvbuf(stdout, NULL, _IONBF, 0);
 
    for (i=1 ; i<argc ; i++) {
        if (!strcmp("-i", argv[i])) {
            error_action = CUEA_IGNORE;
        }
        else if (!strcmp("-f", argv[i])) {
            error_action = CUEA_FAIL;
        }
        else if (!strcmp("-A", argv[i])) {
            error_action = CUEA_ABORT;
        }
        else if (!strcmp("-s", argv[i])) {
            mode = CU_BRM_SILENT;
        }
        else if (!strcmp("-n", argv[i])) {
            mode = CU_BRM_NORMAL;
        }
        else if (!strcmp("-v", argv[i])) {
            mode = CU_BRM_VERBOSE;
        }
        else if (!strcmp("-e", argv[i])) {
            return 0;
        }
        else {
            printf("\nUsage: BasicTest [options]\n\n"
                "Options: -i ignore framework errors [default].\n"
                " -f fail on framework error.\n"
                " -A abort on framework error.\n\n"
                " -s silent mode - no output to screen.\n"
                " -n normal mode - standard output to screen.\n"
                " -v verbose mode - max output to screen [default].\n\n"
                " -e print expected test results and exit.\n"
                " -h print this message and exit.\n\n");
            return 0;
        }
    }
 
    /* 初始化registry */
    if( CUE_SUCCESS != CU_initialize_registry())
    {
        return CU_get_error();
    }
    else
    {
        /* 增加测试套件suite */
        AddTests();
 
        /* 用不同模式运行 */
        /*CU_basic_set_mode(mode);
        CU_basic_run_tests();*/
 
        CU_automated_run_tests();
 
        /*CU_console_run_tests();*/
 
        /* 清除registry */
        CU_cleanup_registry();
    }
 
    return 0;
}

发表您的评论

您的名字:

您的邮箱: (*不会被公布

您的网站: