CUnit介绍

2023-10-27

http://blog.csdn.net/jiantiantian/article/details/3546887

一:概述

二:详细介绍

1:测试函数的书写

2:CUnit提供的断言

3:注册所要进行的测试

4:运行测试和测试报告的生成

5:错误处理

三:注意

 

一:概述

CUnit是一个c语言的单元测试框架,它是以静态链接库的形式,连接到用户代码中的,主要的功能就是提供了语义丰富的断言和多种测试结果输出接口,可以方便地生成测试报告。

但是需要注意的地方是,由于Cunit和我们的代码是在同一个项目中,所以,需要注意将测试代码和程序代码进行区分管理,避免直接在程序代码中添加测试代码;为了达到这个目的,我们经常需要提供单独的头文件,在这个头文件中,可以将原有接口函数罗列进来,还可以将需要测试的内部使用的函数列入,这样,在测试用的.c文件中,就可以直接引用该头文件进行编译,连接,测试。

Cunit测试框架中,测试的层次如下

                      Test Registry
                            |
             ------------------------------
             |                            |
          Suite '1'      . . . .       Suite 'N'
             |                            |
       ---------------             ---------------
       |             |             |             |
    Test '11' ... Test '1M'     Test 'N1' ... Test 'NM'

一个Registry可以认为是一个需要测试的独立的功能集合单元,我们可以使该单元处于active状态,以便进行运行测试,也可以使之处于inactive状态,这样,在一个运行中,我们可以指定要运行的Registry

一个Suite可以若干运行条件类似的测试的集合,他需要注册到某一个Registry才可以被运行到。划分Suite的标准是多样的,例如,某些test运行之前需要进行特定的初始化动作,那么我们可以把凡是需要该类初始化动作的test放入到一个Suite中,因为以Suite为单位,可以有自己的初期化函数和清理函数。

一个test就可以认为是一个单元测试的函数了,由于Cunit是一个黑盒测试工具,也就是说,他的主要目的是根据输入参数和返回结果来从外部观察函数执行的是否正确,所以,通常的做法就是我们提供多种输入,然后使用Cunit提供的断言,来判断返回值,out形参数,和函数可能影响的全局变量的变化是否符合我们的设计。

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

如上边所示,后两种主要是interactive的接口,就是我们可以交互式地指定参数,然后观察结果。在我们具体的环境下,我们通常使用上面两种接口,第一种是将结果输出到XML文档中,便于我们生成报告。第二种仅仅是每一次运行结束之后,在standard output中显示,不能保留测试结果数据。

我们可以将前两种输出结合起来,自己测试的时候,使用Basic模式,生成报告的时候,使用Automated模式。

 

二:详细介绍

1:测试函数的书写

              下面介绍一下典型的测试程序的书写流程:

1) 首先针对被测试的函数书写测试函数。

2) 初始化一个Registry

3) 将特定的Suite加入到这个Registry中。可以为Suite指定初始化函数和清理函数。

4) 将测试函数加入到一个Suite中,这样,如果该测试函数的运行需要一些初始化条件,那么可以可以将代码加入到Suite的初始化函数中,当然不要忘记最后还要做对应的清理操作。

5) 使用相应的接口将测试结果输出。

6) 最后,清理Registry

下面的程序是一个典型的例子:程序段1如下

这个例子中,有两个Suite,同时自己定义了一个函数来将test加入到Suite中,这样的目的是避免main函数太长。另外这个函数中同时使用了Automated接口和Basic接口。我们不必同时使用,可以根据需要的形式进行选择。需要注意的是,使用Automated接口是,需要调用CU_list_tests_to_file()函数。

 

2:CUnit提供的断言

CUnit提供了大量的预定义的断言,针对几乎所有的C的标准类型,我们可以针对具体的需要检查的参数的类型进行选择。

    提供的断言有:

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.

可以看到,每一种类型的断言都有FATAL和非FATAL两个函数,他们的区别是,非FATAL断言失败的时候,程序继续运行,而FATAL类型的断言失败之后,程序马上中止。通常我们使用非FATAL就可以了。

注意在我们的程序中,需要对返回值,out参数进行判断,对于是否是预想结果的判断的时候,一定要使用断言,而不要使用printf等等函数,一方面printf缺乏灵活性,另一方面,只有使用断言,结果报告中才会有对应的输出项。

CU_PASSCU_FAIL这两个断言比较特殊,它们仅仅表示测试程序运行到了这个地方。比如,在某些测试函数中,被测试的函数没有任何返回值等,我们为了证明这个函数已经被运行到了,我们使用以上两个函数。它们仅仅打印出一条消息,代表执行过。还有就是,它们也被输出。

下面程序段2给出了一个被测函数和一个测试函数,注意断言的使用:

 

测试用例是否完备,需要测试人员自己保证。

 

3:注册所要进行的测试

   测试程序书写完成之后,我们需要将它们添加到某一个Suite中,在程序段1中我们看到了如何将一个Suite添加到Registry中,下面我们看看Suite的初始化和清理函数,以及如何将tests添加到Suite中。以下是Suite的初始化和清理程序段3

             

这两个函数是在将Suite添加到Registry的时候指定的。参见程序段1CU_add_suite函数的参数。

下面程序段4显示如何将tests加入Suite,以及测试函数本身

其中,testWRITE_GROUP是一个函数名。函数如下:

其中,write_group就是被测函数。       

 

4:运行测试和测试报告的生成

              完成了以上步骤之后,剩下的就是生成测试报告了:以下是Basic模式下的典型的输出:

表中显示了一共有多少个Suite,多少个tests,还有一共执行了多少个断言.(当然,以上这么多断言是因为有循环。)

如果有失败的断言,那么会是如下的样子,在程序中,我们将write_group进行调整,让断言失败。

以上可以看出,报告会指出断言失败的tests数目,还可以指出,断言失败的位置和函数。

 

关于Automated模式的,如下所示:表一是测试结果的报告,显示该XML文档,需要相关的XSL文档和DTD文档。test_report_multiuser-Results

 

 

 

 

Running Suite Suite(need not init multiuser data)

 

Running test test of get_key() ...

Passed

 

Running test test of original crypt and decrypt ...

Passed

 

Running test test of read_group() ...

Passed

 

Running test test of crypt and decrypt ...

Passed

 

Running test test of mu_load_multiuser_files() ...

Passed

 

Running test test of test parameter check functions ...

Passed

 

Running test test of free_list() ...

Passed

Running Suite Mysuite(need load multiuser data

 

Running test test of get_admin_info() ...

Passed

 

Running test test of mu_get_all_user_info() ...

Passed

 

Running test test of find_user() ...

Passed

 

Running test test of write_group() ...

Passed

 

Running test test of mu_login() ...

Passed

 

Running test test of mu_logout() ...

Passed

 

Running test test of mu_islogin() ...

Passed

 

Running test test of mu_user_authentication() ...

Passed

 

Running test test of mu_modify_password() ...

Passed

 

Running test test of mu_modify_settings() ...

Passed

 

Running test test of mu_get_user_settings() ...

Passed

 

Running test test of mu_register() ...

Passed

 

Running test test of mu_pop_is_busy() ...

Passed

 

Running test test of add_to_list and remove_from_list ...

Passed

Cumulative Summary for Run

Type

Total

Run

Succeeded

Failed

Suites

2

2

- NA -

0

Test Cases

21

21

21

0

Assertions

5241

5241

5241

0

File Generated By CUnit at Mon May 22 11:35:57 2006

表二是关于测试用例的报告:test_report_multiuser-Listing

 

Total Number of Suites

2

Total Number of Test Cases

21

 

Suite

Suite(need not init multiuser data)

Initialize Function?

Yes

Cleanup Function?

Yes

Test Count

7

Test Cases

test of get_key()
test of original crypt and decrypt
test of read_group()
test of crypt and decrypt
test of mu_load_multiuser_files()
test of test parameter check functions
test of free_list()

 

Suite

Mysuite(need load multiuser data

Initialize Function?

Yes

Cleanup Function?

Yes

Test Count

14

Test Cases

test of get_admin_info()
test of mu_get_all_user_info()
test of find_user()
test of write_group()
test of mu_login()
test of mu_logout()
test of mu_islogin()
test of mu_user_authentication()
test of mu_modify_password()
test of mu_modify_settings()
test of mu_get_user_settings()
test of mu_register()
test of mu_pop_is_busy()
test of add_to_list and remove_from_list

 

File Generated By CUnit at Mon May 22 11:35:57 2006

 

5:错误处理

对于Cunit本身运行时的错误有可能使我们误认为是被测程序的错误,这样不利于错误的定位,因此Cunit提供了本身的错误处理函数,主要是以下两个:

CU_ErrorCode CU_get_error(void)
const char* CU_get_error_msg(void)

几乎所有的Cunit函数在发生错误的时候,都会设置相应的错误码,我们可以诊断出到底发生了什么:错误码如下:

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.

三:注意

1:我们应该重视测试程序代码本身的书写。

              2:注意测试代码本身也需要进行相应的错误处理和资源回收,否则在后续的测试工程中,使用资源检查工具诊断出来的泄漏通常是测试代码的问题。

              3:一定要使用断言,不要使用自定义函数。

              4:主要保持测试代码和被测代码的相互独立,尽量不要改动被测试代码。

              5:注意单元测试的测试用例的完备性,对于参数的不同情况,需要考虑是否已经将所有的可能全部覆盖。

              6:注意测试代码的覆盖性,Cunit仅仅运行测试人员写下的程序,如果你不为被测函数写测试代码,它就不会被运行到。

              7:注意保持测试代码的自动化,保证每一次都可以正确运行。比如一个函数设置一个全局变量,仅仅在某些状态下才可以正确执行,那么设置完成,并断言成功之后,需要将这个全局变量恢复到初始值,一方面,可以保证下次执行还是正确的,另一方面,可以减少对其他测试函数的影响。(当然不能一概而论,可以根据具体的情况适用该条款)

              8Cunit用于维持自动的测试环境和测试用例,以便在进行了修改之后,继续检查接口是否发生了变动,以及接口是否正确。他不是一个调试工具,不要将使用debug才可以运行的代码加入进来。

             

具体请参照http://cunit.sourceforge.net/documentation.html
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CUnit介绍 的相关文章

  • 单例模式---Java实现

    单例模式涉及到一个单一的类 该类负责创建自己的对象 同时确保只有单个对象被创建 这个类提供了一种访问其唯一的对象的方式 可以直接访问 不需要实例化该类的对象 注意 1 单例类只能有一个实例 2 单例类必须自己创建自己的唯一实例 3 单例类必

随机推荐

  • Keil编辑和STM32cubemx配置STM32控制步进电机

    使用Keil ARM V5 IDE编程和STM32CUBEMX代码配置实现STM32F103和步进电机驱动器模块A4988控制步进电机 Keil和Stm32cubemx 安装 安装Keil IDE非常简单 下载包含Keil IDE的MDK
  • 基于UmiJs开发移动端的自适应配置方案

    在移动端开发过程中 响应式布局是必须要考虑的一个问题 基于UmiJs开发时 使用的组件库是antd mobile 通过在 umirc js中添加配置项 及可以通过对于的postCss插件postcss px to viewport解决响应式
  • 转载 十分钟理解Actor模式

    Actor模式是一种并发模型 与另一种模型共享内存完全相反 Actor模型share nothing 所有的线程 或进程 通过消息传递的方式进行合作 这些线程 或进程 称为Actor 共享内存更适合单机多核的并发编程 而且共享带来的问题很多
  • 【C++】哈希和unordered系列封装

    1 哈希 1 1 哈希概念 顺序结构以及平衡树中 元素关键码与其存储位置之间没有对应的关系 因此在查找一个元素时 必须要经过关键码的多次比较 顺序查找时间复杂度为O N 平衡树中为树的高度 即O l o g 2 N
  • XMind 各版本官网下载地址

    本博文为备份用 所有链接皆为官网地址 请勿无耻举报 本文仅为软件备份用 方便大家下载官方原装软件 以下版本皆非最新版本 仅备份未列于官网上的软件 其他软件自行去这里下载 http www xmind net download previou
  • 解决Error L6218E Undefined symbol XXX....问题

    分享一个keil的错误编译提示以及其问题解决方法 当我们碰到 Error L6218E Undefined symbol XXX 这个错误提示 其实出现这问题的原因就是我们调用了没有定义的函数 就比如你把一个函数定义注释了 然后却在程序调用
  • Arduino STM32F103C8T6(BluePill) 教程六 STM32 IO操作(LED灯蜂鸣器继电器ADC/PWM)

    Arduino STM32F103C8T6 BluePill 教程六 STM32 IO操作 LED灯蜂鸣器继电器ADC PWM 1 IO操作的 pinMode 函数 形式 void pinMode uint8 pin WiringPinMo
  • eNSP入门介绍(超级超级详细!!!)

    Ensp Enterprise Network Simulation Platform 是华为提供的一款网络仿真平台 主要用于学习 实践和测试企业网络场景 Ensp可以模拟各种网络设备 如交换机 路由器 防火墙等 创建以太网 无线网络等多种
  • COLMAP稀疏重建得图像内外参文件

    前言 一 DTU数据集 二 COLMAP操作步骤 1 安装COLMAP 2 COLMA稀疏重建 总结 前言 整个流程是 第一节用COLMAP求出DTU训练数据集内外参数 第二节处理COLMAP得到的images txt文件中外参 一 DTU
  • listview添加数据_ListView 使用详解

    和你一起终身学习 这里是程序员Android 经典好文推荐 通过阅读本文 您将收获以下知识点 一 ListView 简介二 ListView 常用属性三 ListView主要使用方法如下四 使用android entries 为ListVi
  • 用set_series_opts在PyEcharts中实现系列配置

    全局配置项可通过 set global opts 方法设置 笔记仅是个人的学习笔记总结 如有雷同请见谅 系列配置顶 用法 1 先创建数据 from pyecharts charts import Bar from pyecharts fak
  • 开启XP远程桌面的网络级身份验证(NLA)模式

    indows XP SP3下不支持网络级别身份验证 而Vista Windows 7则支持 那么 何谓网络级身份验证呢 网络级别身份验证 NLA Network Level Authentication 是一种新的身份验证方法 在你建立远程
  • YOLOV3实战6:显示中文标签(YOLOV3中文标签)

    一 番外说明 大家好 我是小P 今天在此给大家分享一下基于DarknetAB版本的YOLOV3如何生成和显示中文标签的方法 效果如下图所示 希望大家支持和喜欢 此外 对 目标检测 模型压缩 语义分割 感兴趣的小伙伴 欢迎加入QQ群 8132
  • openwrt在7620A上对fat格式U盘的支持

    openwrt刷好的固件 在7620a上运行时 可以看到设备节点 但是mount一直提示codepage cp437 not found make menuconfig发现 确实对cp437没有选 路径在Kernel modules gt
  • Swift5.X版本StoreKit原生内购

    内购是移动端一值在讨论的话题 每次上架内购功能要做好被拒的准备 小萌在2年前也做过内购 是OC版本 回想那段往事一把血泪呀 被拒了无数次才把内购功能送上AppStore 小萌之前的OC内购 中间也经历了不少的困难 详情请看苹果内购审核那些被
  • stc单片机使用外部中断+EC11编码器实现计数功能

    stc单片机使用外部中断 EC11编码器实现计数功能 相关篇 STC15 8单片机特有的PWM寄存器和普通定时器实现PWM输出 串口输出测试效果 EC11编码器原理图 EC11编码器输出信号说明 检测说明 以EC11 A信号作为一个时钟基准
  • 基于session的验证方式和Token验证方式的区别,以及JWT的具体实现流程

    1 传统的cookie认证过程 长期以来 基于Session的认证 Session based authentication 一直处于主流地位 由于http协议是无状态的 借助cookie 客户端登陆成功后 服务端就能识别其后续请求 而不需
  • 一篇文章帮你搞定JQuery

    一篇文章帮你搞定JQuery 1 动画 1 1 三种方式显示和隐藏事实 1 1 1 默认显示和隐藏方式 1 1 2 滑动显示和隐藏方式 1 1 3 淡入淡出显示和隐藏方式 2 遍历 2 1 js的遍历方式 2 2 jq的遍历方式 3 事件绑
  • 腾讯云函数SCF初探

    前不久的微信开发者大会上在推他们的Serverless架构 即他们的产品腾讯云函数SCF 当然这个也不是新鲜的事物 在亚马逊提供的同类服务叫做lambda 阿里云提供的则叫做函数计算 Cloudflare的则名为workers 在编程语言的
  • CUnit介绍

    http blog csdn net jiantiantian article details 3546887 一 概述 二 详细介绍 1 测试函数的书写 2 CUnit提供的断言 3 注册所要进行的测试 4 运行测试和测试报告的生成 5