C语言单元测试embUnit入门学习
本人原创,转载请注明出处。
目录
学习目标
2.c语言面向对象编程
2.1c语言继承实现
2.1.1子类结构体包含父类结构体
2.1.2子类结构体包含父类结构中的指针
2.1.3结构体和指针有何不同
2.2其他参考
2.2.1宏定义
2.2.2标准库实现StdImpl
3embUnit学习
3.1总体说明
3.2类图
3.3TestRunner调用过程
3.4TestCaller调用过程
3.5TestResult分析
3.6TestUI分析
学习目标
以前一直从事底层驱动和应用开发,这几年中一直从事应用开发,采用C++去实现,最近由于工作原因,需要用C语言进行产品开发,想找一个c语言的单元测试框架,网上找了一个embUnit,这个库不依赖于标准库,方便进行移植,可以在嵌入式和PC上运行。在看代码的过程中,发现这个库的C语言编写,采用了类似C++面向对象的编程,面向对象C++上还算比较熟悉,但C实现还需要补补。由此便有了两个目标。
1)学习该开源库的c语言面向对象编程以及其编程习惯
2)学习embUnit,做为后面工作c语言单元测试框架
2.c语言面向对象编程
下面只是自己对简单的c语言面向对象编程做一个简单的总结记录。有不对之处,请提出讨论。
2.1c语言继承实现
我们知道c语言只能用结构体来实现C++语言类的概念。那怎么样才能继承呢。总结一句话。当一个类的结构体开始格式数据与另一个类结构体格式相同时。那这两个类可以作为父子类。
2.1.1子类结构体包含父类结构体
例如:
typedef void(*aFunc)();typedef struct __Father{aFunc sFuc;char* sName;
}Father,*pFather;typedef struct __ChildS{Father sFather;char *sFav;
}ChildS,*pChildS;
ChildS结构体开始格式是Father sFather结构体,那ChildS就可以作为Father子类。
测试一下
static void _helloADo(){printf("helloADo....\r\n");
}static const ChildS ChildSA={{_helloADo,"FatherA"},"ChildA"
};pFather pf=(pFather)&ChildSA;
pf->sFuc();
printf("name=%s\r\n",pf->sName);
运行结果如下:
helloADo....
name=FatherA
说明ChildS,可以作为Father子类
2.1.2子类结构体包含父类结构中的指针
参考embUnit采用了另一种方法实现。我们看其中用的最多的Test.
TestImplement是测试抽象实现函数,有点类似于接口概念,纯虚函数。Test是一个类包含TestImplement指针,这时Test作为父类。子类有两个一个是TestCaller和TestCase.下面抽出部分结构体定义。
struct __Test {TestImplement* isa;
};struct __TestCaller {TestImplement* isa; char *name; void(*setUp)(void);void(*tearDown)(void);int numberOfFixtuers;TestFixture *fixtuers;
};struct __TestCase {TestImplement* isa;char *name;void(*setUp)(void);void(*tearDown)(void);void(*runTest)(void);
};
还是记住可以继承的原则。当一个类的结构体开始格式数据与另一个类结构体格式相同时。那这两个类可以作为父子类。这里需要好好理解一下。
所以你看void TestRunner_runTest(Test* test),运行测试都是一个Test对象。这时我们就知道 它可以是TestCaller和TestCase。embUnit顶层测试开始是TestCaller.这些是我们自己由一个个测试用例组成的。
2.1.3结构体和指针有何不同
因为c语言这块面向对象编程才刚开始,c好久不用不太熟悉了。只是谈谈我的个人感觉,这个和c语言特性有关。
指针的好处是方便初始化,可以先把IMP的对象初始化好。再填充。而结构体中结构体初始化填充不是很方便。有兴趣的自己可以测试一下。
2.2其他参考
2.2.1宏定义
embUnit大量用宏定义来生成一个对象。如
#define new_TestFixture(name,test)\
{\
name,\
test,\
}
生成一个TestFixture
其他可以自己研究
2.2.2标准库实现StdImpl
可以参考stdImpl,实现了标准库字符串的操作,其中整形转字符串函数,算法比较简洁可以参考下。
3embUnit学习
简单用UML 做了几个类的分析。但毕竟是C语言的,只能大概示意下。
3.1总体说明
三步调用,Start,RunTest,end.
TestRunner_start();
TestRunner_runTest(assertTest_tests());
TestRunner_end();
主要是准备Test对象,
3.2类图
3.3TestRunner调用过程
这里不过多解释,根据代码分析一下就可以
3.4TestCaller调用过程
TestCaller运行中,生成一个TestCase,然后根据我们应用做好的TestFixture,作为runTest函数,然后在依次启动TestCase Run函数依次运行我们的测试用例
3.5TestResult分析
注意我assertTest,只加了一个testASSERT_EQUAL_STRING,打印结果如下
***********************************************************
************** Unit Test Start ***************
***********************************************************
OK (1 tests)
***********************************************************
************** Unit Test End ***************
***********************************************************
问题:
运行assertTest时,明明它有失败的为什么不打印出来呢?
带着问题我们来分析。
new_TestFixture("testASSERT_EQUAL_STRING",testASSERT_EQUAL_STRING),
是调用testASSERT_EQUAL_STRING该函数
static void testASSERT_EQUAL_STRING(void)
{
//接口函数的实现都用TestCaseImplement
//#define new_TestCase(name,setUp,tearDown,runTest)\
// {\
// (TestImplement*)&TestCaseImplement,\
// name,\
// setUp,\
// tearDown,\
// runTest,\
// }
TestCase tcase = new_TestCase("assert_equal_string",NULL,NULL,assert_equal_string_runTest);
verify(&tcase);
}
它会生成TestCase,就是一个Test对象,再看verify
static void verify(TestCaseRef test)
{
TestResult result = new_TestResult(NULL);
test->isa->run(test,&result);
if (result.failureCount == 0) {
TEST_FAIL("fail");
}
}
生成一个TestResult,注意它没有Listner接口。这时再分析TestCase的Run函数
它的result有POP和PUSH的过程,此处自己体会。由于Listner接口。所以
TEST_ASSERT_EQUAL_STRING("123","456"); 此时用的TestResult没有addfail接口。自然没有失败打印。
那如何才能有呢。
两种方法:
- 直接用TestRunner中的TestResult,
- 自己定义TestReult,增加Listener接口。
- 很简单,在添加时如下
new_TestFixture("testASSERT_EQUAL_STRING",assert_equal_string_runTest), 直接添加该运行函数。注意结果如下。
***********************************************************
************** Unit Test Start ***************
***********************************************************
AssertTest.testASSERT_EQUAL_STRING (..\emb\Tests\assertTest.c 95) exp "123" was "456"
run 1 failures 1
***********************************************************
************** Unit Test End ***************
***********************************************************
失败结果打印出来了。
第二种,可以自行添加代码。我加了也可以实现。
3.6TestUI分析
调用方式如下。
先设置Outputer对象可以是Text和XML,格式。这里又是面向对象的应用。
TextUIRunner_setOutputter(TextOutputter_outputter());
TextUIRunner_start();
TextUIRunner_runTest(assertTest_tests());
TextUIRunner_runTest(stdImplTest_tests());
TextUIRunner_runTest(TestCaseTest_tests());
TextUIRunner_runTest(TestCallerTest_tests());
TextUIRunner_runTest(TestResultTest_tests());
TextUIRunner_runTest(RepeatedTestTest_tests());
TextUIRunner_end();
使用方式差不多 ,不做具体分析,
C语言单元测试embUnit入门学习相关推荐
- R语言基础知识入门学习(一)
目录 系列文章目录 一.软件下载 二.基本知识 1. 对象 2. 向量 3. 向量化 4. 因子 总结 系列文章目录 R语言基础知识入门学习(一) 一.软件下载 我们可以通过这个网址对R语言软件进行下 ...
- proteus8单片机c语言仿真教程,入门学习Proteus 8仿真软件以及C51单片机的LED点亮(C语言)——实例...
入门学习Proteus 8仿真软件以及C51单片机LED的点亮(C语言)--实例 一.点亮LED的程序编译 1.打开Keil uVision 4新建一个工程 2.在Atmel下寻找AT89C52芯片并 ...
- stm32f103c8t6c语言教程,STM32f103C8T6入门学习记录.doc
STM32f103C8T6入门学习记录 STM32 自 学 笔 记 作者:忙碌的小姚 新浪微博:@忙碌的小姚 新浪博客: /mlxiaoyao222 目录 STM32 自 学 笔 记1 第一章3 我与 ...
- c语言EasyX库入门学习
直接搬运朋友的 https://blog.csdn.net/sandalphon4869/article/details/80862023 下面是我将几个例子结合运行的总代码,并进行了一些改进和实现方 ...
- 如何零基础学习python语言_零基础如何入门Python语言?有哪些学习建议?
众所周知,Python目前是最受欢迎的编程语言之一,尤其是对于零基础的初学者来说,Python语言更是十分的友好.因此,不少初学者常常会有这样一个共同的疑惑,零基础如何入门Python语言?本文就来给 ...
- 零基础学python语言_零基础如何入门Python语言?有哪些学习建议?
众所周知,Python目前是最受欢迎的编程语言之一,尤其是对于零基础的初学者来说,Python语言更是十分的友好.因此,不少初学者常常会有这样一个共同的疑惑,零基础如何入门Python语言?本文就来给 ...
- python语言怎么学-如何学习Python,以及新手如何入门?
蟹妖... 首先当然是买一个游标卡尺啊,哈哈哈... 而且有了游标卡尺之后你就不寂寞了,因为游标卡尺不估读... 最近据说python还加入了小学课本,这说明 python 是一门小学生都能学会的语言 ...
- python交互式编程入门先学什么_为什么 Python 对于编程入门学习来说,是一门很棒的语言...
在这篇文章里,我会来阐述下为什么我觉得 Python 对于计算机编程入门教学来说是一门很棒的编程语言(对基础编程课程更多观点可以查看这篇文章).这也是从我针对初学者Python 编程教学过程中获得并总 ...
- c语言10个人 三向成绩,C语言入门学习精华:这样学习C语言最有效
C语言入门学习精华:这样学习C语言最有效 c语言死了吗? 本材料描述了使用C语言的高级技能,并努力将您的C语言能力从"基本"提升到"高级".然而,学习态度比学习 ...
最新文章
- 春愁(shunshu)—Mrs. Green Apple (歌词、汉译、罗马音)
- biopython有什么用_BioPython学习笔记
- 2.1.Python字符串处理(去掉空格或者特殊字符、替换操作、查找操作、判断操作、分割合并操作、字符串文档)
- Using jQuery to add a dynamic “Back To Top” floating button with smooth scroll
- Centos下mysql数据库备份与恢复的方法
- python代码该怎么简化_Python开发简化代码的六大技巧
- 05-按钮的基本使用-开发步骤
- Selenium UI自动化测试(一)环境配置
- php让符合条件的复选框选中,多条件查询(复选框条件)
- IIS 7.0与ASP.NET
- header元素 footer元素 hgroup元素
- 优雅的断开连接--shutdown()
- 冒泡法排序c语言源程序,冒泡排序算法实例程序(C语言)
- 怎么把office卸载干净?
- 计算机打开不显示桌面,电脑启动后不显示桌面怎么办
- 国防科大 计算机原理考研试题,国防科技大学考研2003年计算机原理试题
- [南阳OJ-No.33]蛇形填数|在n*n方陈里填入1,2,...,n*n,要求填成蛇形。
- css中flex设置为1是什么意思
- Poi导入校验因单元格格式产生的空对象问题
- Unity说明文档翻译-Time Manager
热门文章
- 小米6系统 android版本是多少合适,“告别”安卓!小米6用上最新国产系统?
- 超越BERT、GPT------屏蔽序列到序列预训练MASS(原理篇)
- css3特效(上下左右晃动效果)
- react组件中的constructor和super小知识
- Luogu P3054 [USACO12OPEN]跑圈Running Laps
- 问道手游服务器找不到,问道手游安卓苹果互通服怎么不显示 鹊桥相会不能互通解决方法...
- oracle 窗口函数查询条件,62.Oracle数据库SQL开发之 高级查询——使用分析函数之窗口函数...
- 去了北京大兴机场后,我果断抛弃首都机场,去北京,首选大兴
- python rot13解密_牛刀小试——Python 2.7下的rot13编码与解码
- 程序员的另一条出路:在赚够钱后,35 岁考公上岸。