转自:http://blog.csdn.net/scucj/article/details/4385630/

CUnit下载地址: http://sourceforge.net/projects/cunit/

CUnit 在线文档帮助:http://cunit.sourceforge.net/doc/index.html

关于CUnit, 本文主要从介绍三方面的内容:

1.CUnit的介绍。

1.1 介绍如何使用CUnit。

CUnit是一个对C语言编写的程序进行单元测试的框架,在线文档说它作为一个静态链接库被链接到用户的测试代码中。它提供了一种简洁的框架来建立测试架构,并提供丰富的断言(Assertion)来测试通用数据类型。除此之外,它还提供了许多不同的结构来运行测试用例和报告测试结果。

(1)CUnit的架构

                      Test Registry

                            |

             ------------------------------

             |                            |

          Suite '1'      . . . .       Suite 'N'

             |                            |

       ---------------             ---------------

       |             |             |             |

    Test '11' ... Test '1M'     Test 'N1' ... Test 'NM'

提到这个框架,为后面如何使用CUnit提供了基础。

先介绍这个框架,从底层往上介绍就两句话:

(1)每个测试用例被包装在一个测试包(suite)中,

(2)每个测试包(suite)是在有效的测试注册单元(Test Registry)中注册的。

对于CUnit来说,它是单线程运行,所以每次只能有一个有效的测试注册单元(Test Registry),这个测试注册单元下面可以包含多个测试包(suite),每个测试包可以拥有多个测试用例。划分测试包(suite)的规则可以自由约定,比如按照模块来划分,一个模块的测试用例集中到一个测试包中(suite)。至于测试用例,则用来测试模块内部的函数。测试用例函数通过提供的各类输入调用被测试的函数,返回执行结果,然后通过CUnit提供的断言来判断被测试的函数是否正确。

(2)测试模式

下面是四种测试模式:

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

第一种模式是将结果输出到XML文档中,便于生成报告。第二种模式是每一次运行结束之后在standard output中显示测试结果,不能保留测试结果数据。第三种模式是console方式的,可以人机交互;前两种模式是非交互式的。第四种只在Unix中使用。

(3)测试的基本流程

1)编写单元测试函数(有必要的话要写suite的init/cleanup函数)。Write functions for tests (and suite init/cleanup if necessary).


2)调用函数CU_initialize_registry()初始化测试注册单元(Test Registry)。 Initialize the test registry - CU_initialize_registry()


3)调用函数CU_add_suite() 将测试包(suite)添加到测试注册单元(Test Registry)中。Add suites to the test registry - CU_add_suite()


4)调用函数CU_add_test()将测试用例添加到测试包(suite)中。Add tests to the suites - CU_add_test()

5)使用合适的接口来运行测试用例。Run tests using an appropriate interface, e.g. CU_console_run_tests


6)调用函数CU_cleanup_registry清除测试注册单元(Test Registry)。Cleanup the test registry - CU_cleanup_registry()

1.2 通过一个例子来说明使用方法。

先说明文件的组织结构:

1.被测试的模块:

(1)文件MainModule.c,定义了一个求和函数cal_num。

(2)头文件MainModule.h,声明了求和函数cal_num。

2.测试用例和测试包

(1)文件TestMainModule.c,定义了测试用例。

3.单元测试运行入口

(1)文件CUnitRunTest.c

各个文件的内容如下:

【1】MainModule.h

    #ifndef __MAIN_MODULE_H__
#define __MAIN_MODULE_H__
#include <stdio.h> //计算两个数之和
int cal_num(int a, int b); #endif

【2】MainModule.c

    #include "MainModule.h"  

    ////计算两个数之和
int cal_num(int a, int b)
{
int c; c = a + b; return c;
}

【3】TestMainModule.c

    #include <stdio.h>
#include <assert.h>
#include "CUnit-2.1-0/include/CUnit/console.h"
#include "MainModule.h" int InitSuite()
{
return 0;
} int EndSuite()
{
return 0;
} int Test_Is_Equal(int a, int b, int real)
{
int result; result = cal_num(a, b);
if(result == real)
{
return 1;
}
return 0;
} int Test_Is_Not_Equal(int a, int b, int real)
{
int result; result = cal_num(a, b);
if(result != real)
{
return 1;
}
return 0;
} void Test1()
{
CU_ASSERT(Test_Is_Equal(3, 4, 7));
} void Test2()
{
CU_ASSERT(Test_Is_Not_Equal(4, 5, 10));
} /*0 表示成功,1表示失败*/
int AddTestMainModule()
{
CU_pSuite pSuite = NULL; /***************
* 1. CU_add_suite 增加一个Suite
* 2. Suite名字 : testSuite
* 3. InitSuite EndSuite:分别是测试单元初始和释放函数,如不需要则NULL传递
****************/
pSuite = CU_add_suite("testSuite", InitSuite, EndSuite); //检测注册Suite情况
if(NULL == pSuite)
{
//return 1;
} /***************
* 1. 注册当前Suite下的测试用例 
* 2. pSuite:用例指针
* 3. "Test1": 测试单元名称
* 4. Test1:测试函数
***************/
if( NULL == CU_add_test(pSuite, "Test1", Test1) ||
NULL == CU_add_test(pSuite, "Test2", Test2))
{
return 1;
} /***另外一种测试方式***************/
/*
CU_TestInfo testcases[] = {
{"Test1:", Test1},
{"Test2:", Test2},
CU_TEST_INFO_NULL
}; CU_SuiteInfo suites[] = {
{"Testing the function cal_num:", InitSuite, EndSuite, testcases},
CU_SUITE_INFO_NULL
}; if(CUE_SUCCESS != CU_register_suites(suites))
{
return 1;
}
*/
/************************************/ return 0;
}

【4】CUnitRunTest.c

    #include <stdio.h>
#include <assert.h>
#include "CUnit-2.1-0/include/CUnit/console.h" extern int AddTestMainModule(); int main()
{ //CU_initialize_registry 注册函数注册一个用例返回CUE_系列异常值
if( CUE_SUCCESS != CU_initialize_registry())
{
return CU_get_error();
} //CU_get_registry 返回注册到用例指针
assert(NULL != CU_get_registry()); //检测是否在执行
assert(!CU_is_test_running()); //调用测试模块完成测试用例
if (0 != AddTestMainModule())
{
CU_cleanup_registry();
return CU_get_error();
} //使用console控制交互界面的函数入口
CU_console_run_tests(); /***使用自动产生XML文件的模式********
CU_set_output_filename("TestMax");
CU_list_tests_to_file();
CU_automated_run_tests();
***********************************/ //调用完毕清除注册信息
CU_cleanup_registry(); return 0;
}

2.在两种不同环境下使用CUnit来上面的例子进行单元测试。

2.1 在Windows XP下,在VC 6.0 集成CUnit来进行单元测试。

(1)自己动手生成链接静态库CUnit.lib。

下载CUnit-2.1-0-src.zip,解压,在CUnit-2.1-0/CUnit目录下,用VC 6.0打开工程文件CUnit.dsp,有个提示,说没有找到workspace文件,不会理会,直接确定。然后在当前打开的工程项目中,点击"FileView",展开文件树形结构,任意点击一个文件打开,然后在最上面的工具栏点击“编译”和“链接”,在CUnit-2.1-0/CUnit目录下就生产CUnit.lib。

(2)在VC 6.0新建一个名为"Test_CUit"的Win32 console application工程,将上面例子中的文件包含进来。

(3)下载CUnit-2.1-0-winlib.zip,解压,把解压的目录CUnit-2.1-0复制到当前的工程目录下。

(4)将CUnit.lib叶复制到当前的工程目录下,并在"Project"->"Settings..."->"Link"->"Object/library modules"中内容的末尾增加CUnit.lib,用空格和前面的静态库文件隔开,然后点击"OK"即可。

(5)在"Test_CUit"工程项目中,在最上面的工具栏点击“编译”->“链接”->“运行”,就可以看到控制台界面。输入相应的操作符号进行对应的操作,不再详述。

备注:在TestMainModule.c的AddTestMainModule()函数中注释掉的部分是第一种测试模式"Automated Output to xml file",默认的模式是第三种控制台模式。把控制台模式注释掉,而把第一种测试模式打开,则运行时会在当前目录下三个XML文件:CUnit-Memory-Dump.xml,TestMax-Listing.xml,TestMax-Results.xml。将这三个文件复制到目录CUnit-2.1-0/share/CUnit下,然后用浏览器打开后两个XML文件,可以看到测试报告的结果。

2.2 在Linux下,利用CUnit来进行单元测试。

1.编译CUnit,编译后,头文件目录在/root/local/include/CUnit中,静态库文件在/root/local/lib/下。

(1)用root用户登录,下载CUnit-2.1-0-src.tar.gz。

(2)tar -zxvf CUnit-2.1-0-src.tar.gz

(3)cd CUnit-2.1-0

(4)./configure --prefix=$HOME/local

(5)make

(6)make install

2.编写一个Makefile文件,放入到在源文件目录中,内容如下:

    INC=-I/root/local/include
LIB=-L/root/local/lib all: MainModule.c TestMainModule.c CUnitRunTest.c
gcc $^ -o test $(INC) $(LIB) -lcunit -lcurses -static
clean:
rm -rf test

3.在源文件目录下执行make命令即可。

4.运行./test即可看见console命令界面。

3.关于断言的使用

CUnit提供了一系列的断言来测试逻辑条件,这些断言的成功或是失败的结果都由CUnit单元测试框架跟踪,并在单元测试结束后可以看到。每个断言测试一个逻辑条件。如果选择"XXX_FATAL"这些断言,意味着断言失败后单元测试用例不再继续执行,所以带"FATAL"的断言版本需要谨慎使用。断言被包含在"CUnit/CUnit.h"这个头文件中声明的。现在就从CUnit的文档说明中摘录它的断言声明。

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

给出两个版本的源代码供下载。注:在VC6.0下面的源文件不能直接在Linux下使用,如果要用,则提示每个源文件的末尾都要加一个换行符。

【1】VC 6.0 的例子

【2】Linux的例子(无法上传.tar.gz格式的文件)

引用及参考资料:

[1]http://blog.csdn.net/colin719/archive/2006/11/29/1420583.aspx

[2]http://cunit.sourceforge.net/doc/introduction.html

[3]http://hi.baidu.com/yshsh/blog/item/ea2e0a735451cb1f8601b029.html

[4]http://blog.csdn.net/jiantiantian/archive/2008/12/18/3546887.aspx

CUnit的用法的更多相关文章

  1. μCUnit,微控制器的单元测试框架

    在MCU on Eclipse网站上看到Erich Styger在8月26日发布的博文,一篇关于微控制器单元测试的文章,有很高的参考价值,特将其翻译过来以备学习.原文网址:https://mcuone ...

  2. 软件工程(QLGY2015)第一次作业小结(含成绩)

    相关博文目录: 第一次作业点评 第二次作业点评 第三次作业点评 Github项目提交 github的代码提交,大部分人都只是提交了单个文件,存在几个问题 请提交完整的项目文件到github 问题:为什 ...

  3. EditText 基本用法

    title: EditText 基本用法 tags: EditText,编辑框,输入框 --- EditText介绍: EditText 在开发中也是经常用到的控件,也是一个比较必要的组件,可以说它是 ...

  4. jquery插件的用法之cookie 插件

    一.使用cookie 插件 插件官方网站下载地址:http://plugins.jquery.com/cookie/ cookie 插件的用法比较简单,直接粘贴下面代码示例: //生成一个cookie ...

  5. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  6. [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法

    一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...

  7. python enumerate 用法

    A new built-in function, enumerate() , will make certain loops a bit clearer. enumerate(thing) , whe ...

  8. [转载]Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结

    本文对Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法进行了详细的总结,需要的朋友可以参考下,希望对大家有所帮助. 详细解读Jquery各Ajax函数: ...

  9. 【JavaScript】innerHTML、innerText和outerHTML的用法区别

    用法: <div id="test">   <span style="color:red">test1</span> tes ...

随机推荐

  1. SAP HR宏 rp-provide-from-last

    运行se11 Database table: 输入 TRMAC 点击display 查看其内容:第14个按钮(ctrl + shift +F10) 再Name 输入:rp-provide-from-l ...

  2. 转: MySQL 赋予用户权限(grant %-远程和localhost-本地区别)

    相关参考资料: MySQL 赋予用户权限命令的简单格式可概括为: grant 权限 on 数据库对象 to 用户 一.grant 普通数据用户,查询.插入.更新.删除 数据库中所有表数据的权利. gr ...

  3. squid常用调试命令

    解压,编译,make ,make install 就不说了.从 make install 后开始.当你的 squid.conf 配置文档按照你的想法修改完以后,启动 squid 之旅就开始了.1,初始 ...

  4. Fragment使用findFragmentById返回null

    @Override public void onClick(View v) { switch (v.getId()){ case R.id.btn1: replaceFragment(new Anot ...

  5. yII中利用urlManager将URL改写成restful风格 这里主要涉及url显示样式

    1.打开config文件夹下面的mian.php   2.修改内容   如把地址http://www.test.com/index.php?r=site/page/sid/1修改为http://www ...

  6. bzoj3745: [Coci2015]Norma

    Description Input 第1行,一个整数N: 第2~n+1行,每行一个整数表示序列a. Output 输出答案对10^9取模后的结果. 预处理每个位置的数作为最小/大值向左延伸的最大距离, ...

  7. (C#) Tasks 中的异常处理(Exception Handling.)

    多线程编程中要注意对线程异常的处理.首先写个例子. 一个线程用于显示信息(Show Messages).主线程用于做其他工作(Do Works). using (Task taskShowMessag ...

  8. Eclipse启动Tomcat后无法访问项目

    Eclipse中的Tomcat可以正常启动,不过发布项目之后,无法访问,包括http://localhost:8080/的小猫页面也无法访问到,报404错误.这是因为Eclipse所指定的Server ...

  9. Android String操作

    android String.valueOf(ch).getBytes("GBK") --------------------------------------------- S ...

  10. centos之Haproxy 负载均衡学习笔记

    HAProxy的特点是:1.支持两种代理模式:TCP(四层)和HTTP(七层),支持虚拟主机:2.能够补充Nginx的一些缺点比如Session的保持,Cookie的引导等工作3.支持url检测后端的 ...