转自: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. Codeforces Round #161 (Div. 2)

    A. Beautiful Matrix 即相当于求1到中心位置\((2,2)\)的曼哈顿距离. B. Squares 排序,取倒数第\(k\)个即可. C. Circle of Numbers 固定\ ...

  2. [BZOJ 3503][Cqoi 2014]和谐矩阵

    我觉得这一题的样例输出一点都不和谐,大家千万别像我一样被坑了…… 题目不算难,果然是进错省系列555,不过搞出 O(n*m*2m) 的还是不要挣扎的比较好 我们暴力地推出第 n 行 第 m 列中每个数 ...

  3. (转) Deep learning architecture diagrams

    FastML Machine learning made easy RSS Home Contents Popular Links Backgrounds About Deep learning ar ...

  4. 使用as3控制动画

    1.建立按钮元件 2.在属性面板使用英文为按钮元件命名,例如playButton 3.建立函数,例如 function startMovie(event:MouseEvent):void {  thi ...

  5. 九度oj 题目1087:约数的个数

    题目链接:http://ac.jobdu.com/problem.php?pid=1087 题目描述: 输入n个整数,依次输出每个数的约数的个数 输入: 输入的第一行为N,即数组的个数(N<=1 ...

  6. python(25)下载文件

    利用程序自己编写下载文件挺有意思的.Python中最流行的方法就是通过Http利用urllib或者urllib2模块.当然你也可以利用ftplib从ftp站点下载文件.此外Python还提供了另外一种 ...

  7. HoloLens开发笔记之Gesture input手势输入

    手势是HoloLens三个首要输入形式之一.一旦你使用凝视定位了一个全息图像,手势允许你与它交互.手势输入允许你使用手或者点击器原生地与全息图像交互. 手势之外,你也可以在应用中使用语音输入来交互. ...

  8. java io流 对文件操作

    检查文件是否存在 获取文件路径 获取文件大小 ...... 更多参考手册 //对文件的操作 //检查文件是否存在 //获取文件路径 //获取文件大小 //文件是否可读 //文件是否可写 //.... ...

  9. 查看.NET Service Pack版本

    原文地址:如何确定已安装的 Microsoft .NET Framework 版本和 Service Pack 级别 使用以下注册表信息确定已安装的 Microsoft .NET Framework ...

  10. HDU2047

    http://acm.hdu.edu.cn/showproblem.php?pid=2047 对于这道题,我就从后面向前面考虑. 当第n个是o的话,那么n-1 只可以取e或者f,如果n是e或者f的话, ...