当前位置:首页 > > 嵌入式大杂烩
[导读]嵌入式行业摸爬滚打这几年,遇见有规范单元测试的项目寥寥无几。归根到底,无非是公司希望快速迭代出产品,有问题等客户反馈再说。当然,也有人认为是嵌入式行业都是小而美的产品居多,没有到一定量级之前,玩不起单元测试这种配置。不过,出于对代码稳定性的追求,我认为还是应该着手了解一下单元测试的。毕竟,这是有效提高代码说服力的方式之一。


前言

嵌入式行业摸爬滚打这几年,遇见有规范单元测试的项目寥寥无几。归根到底,无非是公司希望快速迭代出产品,有问题等客户反馈再说。当然,也有人认为是嵌入式行业都是小而美的产品居多,没有到一定量级之前,玩不起单元测试这种配置。正如做个蛋炒饭,并不需要安排主厨、二厨一般

不过出于对代码稳定性的追求,我认为还是应该着手了解一下单元测试的。毕竟,这是有效提高代码说服力的方式之一。

相信没有真正体验过单元测试好处的读者一看到"单元测试"这几个字,可能会出现以下两种反应之一:

  • 由于没有单元测试的经验,因此对采用这一方法去保证软件质量很好奇,也迫切地想要了解这一方法在项目中的实施

  • 曾经使用单元测试但效果不好,因为在嵌入式行业,时常要跟硬件打交道,单元测试很难检测硬件问题,所以往往一看到"单元测试"这几个字的反应就是"没用"

如果读者是第一种反应那很好,本文就是科普单元测试的基本要点。如果读者是第二种反应,那可能是对单元测试存在偏见,本系列文章也会介绍mock测试、错误注入等方式,使单元测试也能合理使用于嵌入式行业。



01

单元测试真的"无用"?



造成"单元测试无用论"的第一个原因是,运用这一方法的时机不恰当。不少项目在一开始真正关心质量的人很少,更谈不上采用一整套的方法论去保证质量了。产品在开发出来后发现到处存在问题,只会拆西墙补东墙根本就不能阻止问题一而再,再而三地出现。于是,开始想起单元测试。一声令下,整个项目开始做单元测试。单元测试以模块为单位,需要先把项目拆分出来。如果你的项目代码整体耦合程度较高的话,单元测试根本无从说起,拆分的工作会让你痛苦不已。

单元测试是一项耗时的工作,但管理者却往往希望在短期内看到效果。或者单元测试还没做到位管理层就等不及了,催你马上开始下一步的开发,结果只能是前功尽弃。正确的做法是:在项目的开始之初就引入单元测试。对于以前没有部署单元测试的项目,先只对新增加的、相对独立的模块做单元测试、并逐渐覆盖老代码。

第二个导致"单元测试无用论"的原因是,方法没有运用到位。要保证单元测试的有效性一定要引入另一个概念--代码覆盖。关于代码覆盖,我以后会另外再写一篇文章介绍。只有将单元测试和代码覆盖结合在一起,综合使用才能保证单元测试的效果。

02

最原始的"单元测试"



这里给读者展示一下,不使用任何单元测试框架时,是怎么做单元测试的。

下面简单以linux内核链表为例:

struct list_head { struct list_head *next, *prev;};/*定义一个结构体,只含有表示前驱和后继的指针,它就是我们的主角了*/#define LIST_HEAD_INIT(name) { &(name), &(name) }/*静态初始化*/#define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name)/*动态初始化*/static inline void INIT_LIST_HEAD(struct list_head *list){ list->next = list; list->prev = list;}/*插入操作*//*删除操作*//*合并操作*/...

完整代码很长,这里没有必要全部贴出,能起演示作用就足够了。

现在就以INIT_LIST_HEAD函数为例,来考虑如何为这个函数设计测试用例。INIT_LIST_HEAD函数的实现是如此的简单,以至于很容易让人觉得为它设计单元测试是多余的。但是,从单元测试的角度看,只要不存在可行性问题就不应考虑因为简单而不对其进行验证。而且,放弃对之进行验证,以后会降低代码覆盖率。

做单元测试需要通过编写程序的方式来完成,所编写的用于测试的代码又称为单元测试用例。

下面我们来简单实现一个INIT_LIST_HEAD函数的测试用例:

int main(int argc,char **argv){ struct list_head list;
/*避免函数没有使用参数而引发waining*/ UNUSED(argc); UNUSED(argv);
list.prev = (struct list_head*)0xaaaa; list.next = (struct list_head*)0xbbbb;
INIT_LIST_HEAD(list);
/*检查前指针*/ if(list.prev != list){ return -1; }
/*检查后指针*/ if(list.next != list){ return -1; }
return 0;}

这应该是史上最简单的测试用例,功能非常简单,首先是故意将list结构体中的各个指针变量初始化为一个随机值。然后在调用完INIT_LIST_HEAD函数之后,检查各成员是否被初始化为了list,以判断INIT_LIST_HEAD函数是否正常工作了。注意:这个测试程序还有一个约定,返回-1代表测试失败,返回0表示测试成功。

这个测试用例是基于我们对INIT_LIST_HEAD函数有足够的了解之后编写的,这种测试方法在软件测试领域有个正儿八经的名字,叫白盒测试。

相信通过这个NIT_LIST_HEAD函数的测试用例,你已经初步建立起了对单元测试的印象。但是千万不要以为单元测试仅此而已,这是我刻意简化的结果。要完整地掌握单元测试,还要好好学习一段时间。

目前,对于这个小小的单元测试案例,还有很多的不足,下面简单罗列了几项:

  • 如果对于每一次检查都采取直接写if语句的形式,将造成大量的冗余代码,并且测试用例的编写效率也会很低。

  • 通过观察程序是否返回0或者是-1的方式来判断所有的测试是否通过并不直观,一旦出错也无法马上判断是那一步测试出了问题。毫无疑问,我们需要更加直观的方式来展示哪一步成功或者哪一步失败。

  • 一份严谨的测试用例,会有大量的判定。如果一个测试程序存在100次判定,其中出现了3次失败,那最终显示一个百分比的测试通过率会比较直观,比如可以显示97%的测试成功了。

后面会进一步介绍如何自己搭建一个简单实用的单元测试框架,来解决上面这些问题。也会陆续展开介绍mock方法、打桩、错误注入、代码覆盖、动态分析、静态分析、性能优化等内容。

03

总结


正如很多其他技巧,比如打桌球、滑雪一样,测试驱动开发也要花费相当长时间来练习。许多开发者已经接受了这种技术,而且再也不想回到从前“后期调试式编程”的方式去了。

它会使你的代码:

  •  产生的bug更少

  • 调试时间更短

  • 完全可以通过提交你的单元测试案例,来证明你的项目可靠性。



猜你喜欢

干货 | 函数宏的三种封装方式

你写的程序很健壮?不妨测一下?


1024G 嵌入式资源大放送!包括但不限于C/C++、单片机、Linux等。在公众号聊天界面回复1024,即可免费获取!

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭