单元测试嵌入式软件

时间:2009-06-30 03:57:36

标签: unit-testing embedded

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

10 个答案:

答案 0 :(得分:50)

嵌入式软件在过去10年中可能已经取得了很大进展,但我们通常会做到以下几点:

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

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

答案 1 :(得分:19)

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

  1. 这不适用于测试您的低级代码,包括启动代码,RAM测试,硬件驱动程序。你将不得不使用更直接的单元测试。
  2. 您的嵌入式系统的编译器必须值得信赖,因此您不会寻找编译器创建的错误。
  3. 您的代码必须是分层架构,具有硬件抽象。您可能需要为PC单元测试框架编写硬件驱动程序模拟器。
  4. 您应始终使用stdint.h类型,例如uint16_t,而不是普通unsigned int等。
  5. 我们遵循了这些规则,发现在PC单元测试框架中对应用程序层代码进行单元测试后,我们可以充分相信它运行良好。

    PC平台上的单元测试的优点:

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

答案 2 :(得分:13)

嵌入式系统是一个广泛的主题,但一般来说,让我们将其视为一个结合了硬件和软件的特定用途产品。我的嵌入式背景来自手机,它只是所有嵌入式系统的一小部分。我将尝试在抽象方面略微提出以下几点:

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

  • 尽可能少依赖硬件。

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

答案 3 :(得分:13)

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

答案 4 :(得分:6)

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

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

B)在目标硬件上写下所有内容,但是有一个make目标来有条件地编译一个单元测试版本,它将运行单元测试并通过RS-232或某些输出结果(或可以分析结果的数据)其他方式。如果你没有大量的内存,这可能会很棘手。

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

答案 5 :(得分:6)

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

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

答案 6 :(得分:3)

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

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

答案 7 :(得分:2)

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

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

答案 8 :(得分:0)

eval板上有很多嵌入式处理器,所以虽然你可能没有真正的i / o设备,但通常你可以在这些东西上执行大量的算法和逻辑,通常是硬件通过jtag进行调试。而“单位”测试通常更多地是关于你的逻辑而不是你的i / o。问题通常是让您的测试工件返回 out 其中一个环境。

答案 9 :(得分:0)

在依赖于设备的&之间拆分代码设备无关。独立代码可以在没有太多痛苦的情况下进行单元测试。在您拥有流畅的通信接口之前,需要对相关代码进行手动测试。

如果您正在撰写通讯界面,我很抱歉。