单元测试嵌入式软件[关闭]

Posted

技术标签:

【中文标题】单元测试嵌入式软件[关闭]【英文标题】:Unit Testing Embedded Software [closed] 【发布时间】:2010-11-06 21:27:13 【问题描述】:

您在对嵌入式系统特有的嵌入式软件进行单元测试时使用了哪些最佳实践?

【问题讨论】:

【参考方案1】:

嵌入式软件在过去 10 年中可能取得了长足的进步,但我们通常做了以下工作:

对于不依赖于目标硬件的算法,我们只是在非嵌入式平台上构建和测试了单元测试。 对于确实需要硬件的东西,单元测试被有条件地编译到代码中以使用任何可用的硬件。在我们的例子中,它是目标上的一个串行端口,将结果推送到另一台功能更强大的机器上,在该机器上检查测试的正确性。 根据硬件,您有时可以在非嵌入式平台上模拟“虚拟”设备。这通常包括让另一个执行线程(或信号函数)更改程序使用的内存。适用于内存映射 I/O,但不适用于 IRQ 等。 通常,您一次只能对完整代码的一小部分进行单元测试(由于内存限制)。 对于时间敏感的东西的测试,我们没有。干净利落。如果运行速度太慢,我们使用的硬件(8051 和 68302)并不总是能正常工作。最初必须使用 CRO(示波器)和(当我们有更多钱时)ICE(在线仿真器)进行这种调试。

希望自从我上次这样做以来情况有所改善。我不希望我最大的敌人遭受这种痛苦。

【讨论】:

据我所知,这听起来非常像当前的技术水平。至少,基于过去一年左右使用 TI TMS320 的情况。 你的意思是列出的方法是“最先进的”,我希望。肯定没有人还在使用 8051(68302 没问题,因为我对摩托罗拉 68k 有美好的回忆——它仍然比 x86 IMNSHO 更简洁)?由于开发选项过多,我曾希望所有新的嵌入式开发都在英特尔克隆上完成。 目前正在构建和设计的系统有很多,其中包含基于 8051 的 uC,甚至更多的是 PIC,其架构/性能水平与现代 8051 非常相似。 我赞同在非嵌入式环境中测试算法的想法。这为我节省了大量工作(非常适合通信编码/解码、传感器 ADC 到工程单位计算等)。这似乎是很多书都应该写的那种东西……(MatthewRankin 的回答看起来很有趣)。【参考方案2】:

在 PC 环境中进行单元测试(使用 PC C 编译器编译代码并在 PC 单元测试框架中运行代码)可以获得很多好处,但有以下几个条件:

    这不适用于测试您的低级代码,包括启动代码、RAM 测试、硬件驱动程序。您必须对这些进行更直接的单元测试。 您的嵌入式系统的编译器必须是可信赖的,这样您就不必寻找编译器产生的错误。 您的代码必须是分层架构,具有硬件抽象。您可能需要为您的 PC 单元测试框架编写硬件驱动模拟器。 您应该始终使用stdint.h 类型,例如uint16_t,而不是普通的unsigned int 等。

我们遵循了这些规则,发现在 PC 单元测试框架中对应用层代码进行单元测试后,我们可以确信它运行良好。

PC平台单元测试的优势:

    您不会因为添加单元测试框架而面临嵌入式平台上 ROM 空间不足的问题。 在 PC 平台上,编译-链接-运行周期通常更快、更简单(并且避免了可能需要几分钟的“写入/下载”步骤)。 您有更多选项可用于可视化进度(某些嵌入式应用程序的 I/O 外设有限)、存储输入/输出数据以供分析、运行更耗时的测试。 您可以使用现成的基于 PC 的单元测试框架,这些框架不可用/不适合嵌入式平台。

【讨论】:

【参考方案3】:

嵌入式系统是一个广泛的话题,但总的来说,让我们将其视为结合了硬件和软件的特定用途产品。我的嵌入式背景来自手机,这只是所有嵌入式系统的一小部分。我会尽量在抽象方面保留以下几点:

尽可能抽象出硬件依赖关系。通过这种方式,您可以在模拟的“硬件”上运行单元测试,还可以测试各种难以在目标上测试的罕见/异常情况。为了防止抽象成本,您可以使用例如条件编译。

尽可能少地依赖硬件。

在模拟器或交叉编译器环境中运行的单元测试仍然不能保证代码在目标硬件上工作。您还必须在目标上进行测试。尽早对目标进行测试。

【讨论】:

我将添加到“尽早测试目标”。 - 如果是定制硬件,或者具有重要定制组件的硬件,这会翻倍。【参考方案4】:

您可能想查看 James W. Grenning 的 Test Driven Development for Embedded C。该书计划于 2010 年 8 月出版,但测试版书现已在The Pragmatic Bookshelf 上提供。

【讨论】:

我刚买了这本书。我现在正在转向嵌入式世界,我想在 Microchip C30 上使用单元测试,但遇到了困难。【参考方案5】:

这里是缺乏经验的声音,但这也是我最近一直在考虑的事情。在我看来,最好的方法是

A) 在 PC 环境中尽可能多地编写与硬件无关的应用程序代码,然后再将其写入目标,同时编写单元测试(首先在 PC 上执行此操作应该会有所帮助强迫你分离与硬件无关的东西)。通过这种方式,您可以使用您选择的单元测试器,然后以老式方式测试硬件相关的东西 - 使用 RS-232 和/或示波器以及 I/O 引脚发送与时间相关的数据,具体取决于它的运行速度.

B) 将它全部写在目标硬件上,但是有一个 make 目标来有条件地编译一个单元测试构建,该构建将运行单元测试并通过 RS-232 或一些输出结果(或可以分析结果的数据)其他手段。如果你没有很多内存,这可能会很棘手。

编辑 2009 年 7 月 3 日 我刚刚想到了如何对硬件相关的东西进行单元测试。如果您的硬件事件发生得太快而无法使用 RS-232 记录,但您不想手动筛选大量示波器数据来检查您的 I/O 引脚标志是否按预期上升和下降,您可以使用 PC带有集成 DIO 的卡(例如 National Instruments 的数据采集卡系列)来自动评估这些信号的时序。然后您只需要在您的 PC 上编写软件来控制数据采集卡与当前运行的单元测试同步。

【讨论】:

【参考方案6】:

我们设法使用模拟器测试了相当多的硬件相关代码,我们使用 Keil 的模拟器和 IDE(不附属只是使用他们的工具)。我们编写模拟器脚本以我们期望它做出反应的方式驱动“硬件”,并且我们能够非常可靠地测试我们的工作代码。诚然,为某些测试建模硬件可能需要一些努力,但对于大多数事情来说,这工作得很好,并且允许我们在没有任何可用硬件的情况下完成很多工作。在访问硬件之前,我们已经能够在模拟器中接近完整的系统工作,并且一旦将代码放在真实的东西上,我们几乎没有需要处理的问题。这也可以显着加快代码的生成速度,因为一切都可以在 PC 上完成,使用更深入的调试器,同时模拟芯片而不是尝试在硬件上完成所有事情。

使其能够可靠地用于复杂的控制系统、存储器接口、定制 SPI 驱动 IC 甚至单显示器。

【讨论】:

【参考方案7】:

这里有很多很好的答案,一些没有提到的事情是运行诊断代码以便:

记录 HAL 事件(中断、总线消息等) 有代码来跟踪你的资源,(所有活动的信号量,线程活动) 具有捕获 ram 机制,将堆和内存内容复制到持久存储(硬盘或等效设备),以检测和调试死锁、活锁、内存泄漏、缓冲区溢出等。

【讨论】:

【参考方案8】:

当我去年遇到这个问题时,我真的很想在嵌入式平台本身上进行测试。我正在开发一个库,我正在使用嵌入式平台的 RTOS 调用和其他功能。没有任何具体可用的东西,所以我根据我的目的调整了 UnitTest++ 代码。我在NetBurner 系列上编程,因为它有一个嵌入式 Web 服务器,所以编写一个基于 Web 的 GUI 测试运行程序来提供经典的 RED/GREEN 反馈非常简单。它turned out pretty well,现在单元测试更容易了,我对知道代码在实际硬件上工作更有信心。我什至使用单元测试框架进行集成测试。起初我模拟/存根硬件并注入该接口进行测试。但最终我编写了一些运行实际硬件的人在循环测试。事实证明,这是一种更简单的了解硬件的方法,并且可以轻松地从嵌入式陷阱中恢复。由于测试都是从 AJAX 回调到 Web 服务器运行的,因此陷阱仅作为手动调用测试的结果发生,并且系统总是在陷阱后几秒钟干净地重新启动。

NetBurner 足够快,写入/编译/下载/运行测试周期约为 30 秒。

【讨论】:

【参考方案9】:

评估板上提供了许多嵌入式处理器,因此尽管您可能没有真正的 i/o 设备,但通常您可以在其中一种设备上执行大量算法和逻辑,通常带有硬件可通过 jtag 进行调试。无论如何,“单元”测试通常更多的是关于你的逻辑而不是你的 i/o。问题通常是让您的测试工件退出这些环境之一。

【讨论】:

【参考方案10】:

在设备相关和设备无关之间拆分代码。可以对独立代码进行单元测试而不会有太多痛苦。依赖代码只需要手动测试,直到您拥有流畅的通信接口。

如果您正在编写通信接口,我很抱歉。

【讨论】:

写一个通信接口有那么难吗? @abunickabhi - 很难,也很乏味/令人沮丧。当您通过 LED 进行调试时,构建一个工作依赖于设备的驱动程序可能会非常乏味。 :)

以上是关于单元测试嵌入式软件[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

基于winAMSCasePlayer2嵌入式软件单元测试

基于winAMSCasePlayer2嵌入式软件单元测试

嵌入式单元测试--框架解析

嵌入式软件仿真测试环境是啥意思?

Tessy—支持复杂场景测试的单元集成测试工具

嵌入式代码单元/集成测试工具VectorCAST