CUnit单元测试架构研究

1.Cunit介绍

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

在这里插入图片描述

1.1CUnit的架构

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

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

注册单元下面包含多个测试包,每个测试包可以拥有多个测试用例,至于测试用例,则用来测试模块内部的函数。测试用例函数通过提供的各类输入调用被测试的函数,返回执行结果,然后通过CUnit提供的断言来判断被测试的函数是否正确。

1.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中使用。

1.3 测试的基本流程

1.编写单元测试函数

2.调用函数CU_initialize_registry()初始化测试注册单元(Test Registry)

3.调用函数CU_add_suite() 将测试包(suite)添加到测试注册单元(Test Registry)4.调用函数CU_add_test()将测试用例添加到测试包(suite)5.用合适的接口来运行测试用例 (对应参数模式)

6.调用函数CU_cleanup_registry清除测试注册单元(Test Registry)

2. CUnit配置

2.1CUnit安装配置

将从网上下载的CUnit-2.1-3安装包解压放到ubuntu中,进入CUnit-2.1-3目录输入./configure进行安装,configure是一个安装脚本。

第二步:使用make进行配置

第三步:使用make install (需要root权限也就是需要加sudo)

第四步:编译 /etc/ld.so.conf文件,在文件加上/usr/local/lib

第五步:使用ldconfig命令

注意:如果配置有问题可以尝试添加sudo权限

2.2 CUnit测试安装是否正确

将 http://cunit.sourceforge.net/example.html 页面的例子复制下来,保存为 cunit.c 文件

编译: gcc -o cunit cunit.c -lcunit

运行:./cunit

3.使用实例

3.1.被测试的模块:

(1) 文件ap_math.c,定义了一个求和函数cal_num。
(2) 头文件ap_math.h,声明了求和函数cal_num。

ap_math.c文件

#include "ap_math.h"

int cal_num(int a, int b)
{
   int c;  
   c = a + b;
   return c;
}

ap_math.h文件

int cal_num(int a, int b);

3.2.测试用例和测试包

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

#include <CUnit/Basic.h>
#include <CUnit/Console.h>
#include <CUnit/CUnit.h>
#include <CUnit/TestDB.h>
#include "ap_math.h"

int init_suite()
{
    return 0;
}

int end_suite()
{
    return 0;
}

int test_is_euqal(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()
{   
    int i;
    
    for(i = 0; i < 100000; i++)
    CU_ASSERT(test_is_euqal(3+i, 4, 7+i));  //根据返回值
    
    CU_ASSERT(test_is_euqal(20+i, 20+i, 40+2*i));

}

void test2()
{
    CU_ASSERT(test_is_not_equal(3, 4 ,10));
}

int test_cal_module()
{
    CU_pSuite p_suite = NULL;
    
    p_suite = CU_add_suite("test_suite", init_suite, end_suite);
    if (p_suite == NULL)
    {
        return 1;
    }

   if(CU_add_test(p_suite, "test1", test1) == NULL
        ||CU_add_test(p_suite, "test2", test2) ==NULL)
    {
        return -1;
    }
     
    return 0;
}

这二个函数类型驱动的加载和卸载函数

int init_suite()
{
    return 0;
}

int end_suite()
{
    return 0;
}

test1和test1函数是二个测试样例。分别是test1通过调用CU_ASSERT断言来判断是否通过调用cal_num函数(被测函数)给被测函数传参20,20看其返回值是否能跟预期40相等。test2通过给被测函数传参3,4是否不等于10。

int test_is_euqal(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_euqal(20, 20, 40));

}

void test2()
{
    CU_ASSERT(test_is_not_equal(3, 4 ,10));
}

使用CU_add_suite接口测试包(suite)添加到测试注册单元(Test Registry)中,再使用CU_add_test接口将test1和test2添加到测试包(suite)中。

int test_cal_module()
{
    CU_pSuite p_suite = NULL;
    
    p_suite = CU_add_suite("test_suite", init_suite, end_suite);
    if (p_suite == NULL)
    {
        return 1;
    }

   if(CU_add_test(p_suite, "test1", test1) == NULL
        ||CU_add_test(p_suite, "test2", test2) ==NULL)
    {
        return -1;
    }
     
    return 0;
}

3.3.单元测试运行入口

test_run.c文件

先使用CU_initialize_registry函数进行初始化,然后添加测试用例,在选择用那种控制模式。然后调用CU_cleanup_registry函数其实就是调用上面的end_suite函数。

#include <stdio.h>
#include <assert.h>
#include "CUnit/Basic.h"

extern int test_cal_module ();

int main(int argc, char const *argv[])
{
    if (CU_initialize_registry() != CUE_SUCCESS)
    {
        return CU_get_error();
    }
    
    assert(CU_get_registry() != NULL);
    assert(!CU_is_test_running());
    
    if (test_cal_module() != 0)
    {
        CU_cleanup_registry();
        return CU_get_error();
    }
    
    CU_basic_set_mode(CU_BRM_VERBOSE);
    CU_basic_run_tests();

 //   CU_console_run_tests();

    CU_cleanup_registry();
    return 0;
}

3.4编译链接

编译和运行

gcc -o test ap_math.c test_ap_math.c test_run.c -lcunit

./test

运行结果
在这里插入图片描述

4.断言和测试模式的使用

4.1断言的使用

Cunit提供一系列的断言来测试逻辑条件,这些断言的成功或者失败的结果都是由CUnit框架进行跟踪,并在单元测结束后可以看到。每个断言测试一个逻辑条件,如果我们选择了”xxx_FATAL"断言,也就是说断言一但失败那个单位测试用例就不会再继续执行了。断言是包含在“CUnit/CUnit.h"这个头文件中。

用于判断表达式是否为真(non-zero)

CU_ASSERT(int expression)
CU_ASSERT_FATAL(int expression)
CU_TEST(int expression)
CU_TEST_FATAL(int expression)	

用于判断数值是否为真(non-zero)

CU_ASSERT_TRUE(value)
CU_ASSERT_TRUE_FATAL(value)

判断数据只是为假(zero)

CU_ASSERT_FALSE(value)
CU_ASSERT_FALSE_FATAL(value)

判断是否为等式

CU_ASSERT_EQUAL(actual, expected)
CU_ASSERT_EQUAL_FATAL(actual, expected)

判断是否为不等式

CU_ASSERT_NOT_EQUAL(actual, expected))
CU_ASSERT_NOT_EQUAL_FATAL(actual, expected)

判断指针是否为等式

CU_ASSERT_PTR_EQUAL(actual, expected)
CU_ASSERT_PTR_EQUAL_FATAL(actual, expected)

判断指针是否不是等式

CU_ASSERT_PTR_NOT_EQUAL(actual, expected)
CU_ASSERT_PTR_NOT_EQUAL_FATAL(actual, expected)

判断字符串是否相等

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)

4.2测试模式的使用

这下面是对应于三种模式分别是自动化模式,基础模式,控制模式。

                 /**** Automated Mode *****************/
                 CU_set_output_filename("TestMax");
                 CU_list_tests_to_file();
                 CU_automated_run_tests();
                 /************************************/
                 
                 /***** Basice Mode *******************/
                 CU_basic_set_mode(CU_BRM_VERBOSE);
                 CU_basic_run_tests();
                 //************************************/
 
                 /*****Console Mode ********************/
                 CU_console_run_tests();
                //************************************/

5.CUnit使用总结

如下图所示被测函数由输入一系列参数然后得到结果,跟我们事先设定好的期望值对比,测试是否期望值不符,比如上面一个简单的例子,被测函数是一个二个数的求和函数,咱们向被测函数输入3和4二个求和数,其函数正确执行的话应该是会得到7这个期望值。而7这个期望值balue就是我们事先设定好的。与函数执行完得到的返回值进行比较,通过CUnit框架提供的断言接口来记录这些比较是否有出现异常,如有出现异常会在结果输出中标识出来。

在这里插入图片描述

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: CUnit是一个用于开发和执行C程序的单元测试框架。开发者可以使用CUnit来编写测试用例,以验证程序的各个模块的功能是否正确。以下是CUnit单元测试用例开发的一般流程: 1. 安装CUnit:首先需要从CUnit的官方网站下载并安装CUnit库。 2. 引入头文件:在测试用例的C文件中引入CUnit的头文件,以便使用CUnit的相关函数和宏。 3. 定义测试用例:在测试用例的C文件中,可以使用CUnit提供的宏来定义测试用例及其相关的测试函数。测试函数应该包含一系列测试断言,用于验证被测程序的输出是否符合预期。 4. 初始化测试套件和测试注册:使用CUnit提供的宏和函数,初始化测试套件并将测试用例注册到测试套件中。 5. 执行测试用例:使用CUnit提供的函数,执行测试套件中的所有测试用例。 6. 生成测试报告:CUnit会自动记录测试结果,包括测试通过和测试失败的情况,还可以生成详细的测试报告。 7. 分析和修复错误:根据测试报告,开发者可以分析测试失败的原因,并修改被测程序中的错误。 通过CUnit单元测试用例开发,可以有效地提高程序的质量和稳定性。测试用例可以覆盖程序的各个功能模块,验证其正确性和健壮性。同时,CUnit还能提供详细的测试报告,让开发者更容易发现并修复错误。 ### 回答2: CUnit是一个用于C语言项目的单元测试框架。在软件开发过程中,为了保证代码的质量和稳定性,需要对不同的函数模块进行单元测试CUnit可以帮助开发人员编写和执行这些测试用例。 用CUnit进行单元测试用例开发需要以下几个步骤: 第一步是创建测试用例。测试用例是一段测试代码,用于验证功能模块的正确性。开发人员需要根据功能要求和预期结果,编写一系列测试用例。 第二步是编写测试代码。测试代码中包含了一系列宏和函数,用于定义测试集合、测试套件和测试用例。开发人员需要定义不同的测试集合,并将测试用例添加到相应的集合中。 第三步是执行测试。通过调用CUnit提供的函数,开发人员可以执行之前定义的测试集合。CUnit将自动执行测试用例,并记录测试结果。开发人员可以查看测试结果,以确定功能模块的正确性。 第四步是分析测试结果。通过查看测试结果,开发人员可以了解哪些测试用例通过了,哪些失败了。通过分析失败的测试用例,可以找到代码中的问题,并进行修复。 最后一步是反复迭代测试过程。在软件开发过程中,需要不断进行单元测试,以确保代码的质量和稳定性。开发人员可以修改测试用例和测试代码,并重复执行测试过程,直到代码满足预期结果为止。 通过CUnit单元测试用例开发,开发人员可以更好地验证和调试功能模块,提高代码的质量和稳定性,从而提高整个软件项目的可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值