嵌入式开发的单元测试时的最佳实践


45

我正在寻找一些针对嵌入式系统编写的单元测试代码的最佳实践策略。对于嵌入式系统,我的意思是代码,例如设备驱动程序,ISR处理程序等,它们与金属非常接近。

如果不借助ICE在硬件上进行测试,则无法进行大多数单元测试。有时,嵌入式单元还需要与其他刺激因素挂钩,例如机械开关,步进电机和灯泡。这通常以手动方式发生,自动化虽然很棒,但实现起来却又困难又昂贵。

更新资料

我遇到了一个C测试框架,该框架似乎在测试嵌入式项目中非常成功。它使用了模拟硬件的想法。查看UnityCMock以及可能的Ceedling

更新2016年7月6日

跨过cmocka-似乎正在更加积极地开展工作。


1
在类似情况下,我们去了Cmocka
Mawg '16

我已经写了一个非常详尽的教程,涉及以下主题:使用Ceedling对嵌入式C应用程序进行单元测试
Dmitry Frank

Answers:


28

我将尽早从硬件依赖关系中抽象出来,并在软件仿真/测试工具上构建系统,从而启用各种测试框架。我开发的PC通常用于测试整个系统的95%或更多。额外开销(另一层抽象)的成本很容易被该抽象所生成的更干净的代码所弥补。

嵌入式系统中真正的裸机部件的测试通常是一个单独的应用程序(单元测试?),它将固件的工作范围远远超出了应用程序甚至希望达到的目标。可以实现自动化-需要付出一定的代价,但这并不典型。

除非,也就是说,您没有预算来构建包含完整ICE的单元测试硬件工具。绝对不错,因为通常功能测试很小。


结合乔纳森·克莱恩·艾伊的回答,这是一个成功的策略。使用抽象使大部分代码可测试,并使用简单的测试框架测试实际硬件上的不可抽象位。我亲自看到了在多个平台上的这项工作。
蒂姆·威利斯克罗夫特

3
我们制造的每个产品都具有硬件抽象层,其中包含针对目标平台和PC的驱动程序的实现。这使我们可以轻松地运行单元测试。其他优势:我们还可以运行快速的系统测试,并且无需任何硬件即可开发大多数软件(稍后将提供)。
2011年

15

要开发的必要工具是信号注入器。嵌入式系统将通过某种方式与主机系统接口(通常通过保留用于调试的串行端口)。使用它来发送测试数据(最佳选项是简短的ascii格式,因此也很容易被人模拟)。

我完全不同意您的问题的这一部分:“自动化将是伟大的,但是实现起来却是困难而昂贵的。”

使用TeraTerm作为串行端口信号注入器,并编写一些TeraTerm宏(大约需要20分钟),可以对嵌入式系统的任何部分进行大量的自动化测试,包括驱动程序层,操作系统,第4-5层,等等。TeraTerm:http : //en.sourceforge.jp/projects/ttssh2/

如果嵌入式系统上没有串行端口,请使用硬件工具将USB /串行端口数据转换为数字信号(价格便宜且易于实现)。在您阅读本文时,我正在使用价格为30美元的微控制器板(UBW:http : //www.schmalzhaus.com/UBW32/)通过通过TeraTerm宏注入激励的嵌入式系统来测试生产环境,该激励通过USB /串行接口发送到微控制器,该微控制器运行修改后的固件,该固件可执行数字输入并监视目标嵌入式系统的数字输出。与此结合,我们开发了一个python脚本(使用pyserial和pexpect)来自动化数据注入和数据验证。都不困难,也不昂贵。根据我的经验,当测试团队缺乏经验并且无法构思出这些简单的解决方案时,经理们会花大笔钱(例如30,000美元的测试设备)-不幸的是,通用的大型铁质设备通常不包括测试用例它捕获了目标系统的最坏情况下的时序等。 因此,便宜的方法更适合测试覆盖范围。 信不信由你。


1
好吧,我在汽车行业工作时发表了昂贵的声明,所有事情都需要确定性,可重复性,并且通常需要几个工程师来开发。同样,当在测试链中使用更多项目时,维护也成为问题。感谢您告知我们有关UBW的信息,这似乎是个不错的选择。
tehnyit 2011年

2
只是不要让我开始使用LabView。.通常这是可怕的东西。
Jonathan Cline IEEE

1
我们的测试工程师喜欢LabView,我自己不太了解。
tehnyit 2011年

这与我进行各种测试非常接近,只有我使用Python及其串行库。然后,我可以将我的低级测试以及类似Flask / Qt的东西插入Python的单元测试器中,以提供一个易于使用的前端。
radix07年

5

这是一个非常困难的问题。

我实际上已经为嵌入式系统设计了一个单元测试工具,该工具可以模拟硬件事件/中断,并控制执行的时间(以确保我们涵盖由于并发而引起的所有可能的交错),并且花了一个团队。程序员需要2年以上的时间才能真正实现并投入使用。该项目是专有开发,但此处提供类似(设计简单)的项目。

所以是的,自动化会很棒。是的,这是非常困难且昂贵的。是的,有时您必须这样做。但是,以我的经验,在大多数情况下,使用步进电机和灯泡并使其全部手动工作更快捷,更便宜,这很少。


我发现手动生成的单位容易出错,通常是在产生刺激或测量结果方面。如果单元测试很复杂,则尤其如此。如果您必须再次重做单元测试,它更容易出错。
tehnyit,2011年

@tehnyit-是的,这就是我们决定开发自动化系统的原因。有时事情根本无法手动完成,但是单元测试需要全面并且涵盖时序问题。因此,您没有太多选择,但是在此级别进行自动化一件非常昂贵的事情。
littleadv

4

编辑:我的答案接近于mattnz的,我想...


我想将此问题与其他所有依赖于代码外部的测试(例如系统时钟,持久性文件系统或数据库,与外部Web服务的联系...)相关联。我对所有这些建议相同的策略,将两个级别隔离在两层代码中。

测试单个外部操作

您可能需要对每个操作进行物理测试。检查系统时钟是否给出了正确的时间,检查文件实际上是否记得已写入的内容,检查设备是否执行了单个操作...

这些测试:

  • 应该尽可能简单:没有算法,没有条件或循环
  • 可能取决于订单和取决于机器:因此您需要遵循严格的订单,并在每个硬件上重复
  • 在您的项目过程中大多数情况下都是稳定的,因此您不需要经常运行它们
  • 因此手动运行它们是一种选择; 自动化甚至更好,即使不是太复杂
  • 请注意,所测试的不是您的代码,而是您的代码所需要的工具...因此,这对于您来说可能是可选的,它可能是由其他团队完成的...

测试将外部操作挂钩的逻辑(代码,算法)

通过使用一层代码来执行实际的外部操作,将它们隐藏在一个您可以轻松模拟的接口中,您的逻辑不再依赖于实际的物理设备...

您可以像任何常规项目一样简单地进行测试,而不再需要嵌入嵌入式的难以测试的代码


3

嵌入式CPU模拟器通常可以编程为也模拟硬件。Xen以外的所有虚拟化技术都可以做到这一点。但是,您需要编写代码,假装在某个物理地址或在x86上的I / O总线地址上有一些寄存器,然后您需要对这些地址的读取和写入做出响应,就好像您的软件是物理地址一样。正在访问其控制和状态寄存器的芯片。

如果您想这样做,我建议您修改QEMU。但这并不容易。通常,只有在设计带有微控制器和I / O的其他内核的定制芯片时,才可以执行这种操作。

ARM Holdings出售的开发系统可提供此功能,并且比在QEMU上进行黑客攻击更容易使用,但价格昂贵。

有几种运行单个子例程的开源ARM仿真器,它们本身可以调用其他子例程,您可以将其用于调试调整不依赖于硬件访问的子例程的性能。我成功地使用其中之一来优化ARM7TDMI的AES加密器。

您可以用C或C ++编写一个简单的单元测试工具,将要测试的类或子例程链接到它,然后在模拟器中运行。

多年来,我一直在思考类似的问题,即如何对Linux或Mac OS X内核代码进行单元测试。应该有可能,但我从未真正尝试过。一种可能是构建一个完整的内核,而不是孤立地测试您的代码,而将单元测试框架直接链接到您的内核中。然后,您可以从某种外部接口启动单元测试。

使用代码覆盖率工具,然后通过其外部接口将固件作为一个完整的软件包进行测试,可能会更有效率。Coverage工具会查找尚未测试的代码路径,因此您可以添加其他外部测试,以尝试获得更大的覆盖范围。


3

与非嵌入式TDD一样,模拟对象绝对是您的朋友。

保持与底层硬件的接口简洁明了,以便可以嘲笑最低层之上的所有内容,并且可以轻松得多。如果您在设计嵌入式应用程序时考虑到可测试性,那么测试总是会更加顺利。

另外,仅仅因为您可能直到项目后期才可以进行在线测试,并不意味着您也不应该准备一套在线测试。

这些(最初)应该只需要测试无法离线测试的位。当然,这不是TDD(因为您是预先创建测试),但是您的离线TDD开发应该使您对硬件接口的外观以及所需执行的在线测试有所了解。

此外,如果在线开发的成本比离线开发高(在我工作的地方也是如此),那么它可以为您节省大量的在线时间,其中包含一组易于理解的测试。


+1用于将模拟对象带到@mark板上。一个问题是确保模拟对象的准确性,这意味着对要模拟的对象的理解应该非常深入。这很好,因为它迫使开发人员了解与其连接的外部对象的行为。
tehnyit 2011年

1

在嵌入式开发中,您经常进行边界扫描以验证整个应用程序(包括硬件)是否正常工作。另请参阅JTAG以进行系统调试。

可以通过标准的C单元测试框架(如Check)来测试没有链接到硬件的纯软件例程。但要注意内存限制(尤其是小型设备上的堆栈空间等)。了解您的合同!您也可以尝试从硬件中提取软件例程,以获得更大的测试覆盖范围,但是就嵌入式设备(如小型PIC或AVR)的性能而言,这通常会付出高昂的代价。但是,您可以模拟硬件端口以实现更大的覆盖范围(当然,您也可以测试该模拟)。

您也可以尝试将仿真器用于芯片或电路仿真器,但是这类工具价格昂贵(尤其是组合使用)且复杂。


同意边界扫描和JTAG,但是由于硬件设计的原因,它并非总是可行或可用的。
tehnyit,2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.