如何使用硬件进行 TDD
Posted
技术标签:
【中文标题】如何使用硬件进行 TDD【英文标题】:How to do TDD with hardware 【发布时间】:2009-02-25 11:04:18 【问题描述】:我工作的所有项目都与一个硬件接口,这通常是该软件的主要目的。有什么有效的方法可以将 TDD 应用到适用于硬件的代码?
更新:抱歉,我的问题没有更清楚。
我使用的硬件是从相机捕获图像的图像采集卡。然后我处理这些图像,显示它们并将它们保存到磁盘。我可以使用存储在磁盘上的先前捕获的图像来模拟捕获图像后发生的所有处理。
但我要测试的是与硬件的实际交互。例如,当没有连接相机时,我的软件是否正确处理,它是否正确启动和停止抓取等。但这与硬件紧密相关,我不知道当硬件不存在时如何测试它或如果我什至应该尝试这样做?
第二次更新:我也在寻找一些具体的例子来说明人们是如何处理这种情况的。
【问题讨论】:
您的问题只是关于测试与硬件接口的代码,还是关于以这种方式测试硬件? 我猜两者都是,但我与硬件交互的代码是相当薄的一层。它只是调用实际控制硬件的第 3 方库。 这个问题的真正症结在于,如果所讨论的硬件能够完全用软件描述,那么你就不需要硬件了。 :P 【参考方案1】:创建一个薄层来控制硬件,并使用完整硬件的系统测试(手动或自动)来确保控制层按预期工作。然后创建控制层的假/模拟实现,它的外部行为类似于真实硬件的接口,并在为程序的其余部分执行 TDD 时使用它。
几年前,我正在编写使用 SQUID 磁力计进行测量的软件。硬件很大,不可移动且昂贵(video),因此不可能始终访问硬件。我们有关于与设备的通信协议(通过串行端口)的文档,但文档并非 100% 准确。
对我们帮助很大的是创建了一个软件,它可以监听来自一个串行端口的数据,记录它并将其重定向到另一个串行端口。然后我们能够找出旧程序(我们正在替换)如何与硬件通信,并对协议进行逆向工程。它们是这样链接的:旧程序 虚拟环回串行端口 我们的数据记录器 真实串行端口 硬件。
那时我们没有使用 TDD。我们确实考虑过为硬件编写一个模拟器,以便我们可以单独测试程序,但是由于我们不知道硬件应该如何工作,所以很难编写一个准确的模拟器,所以最后我们没有做。如果我们更了解硬件,我们可以为它创建一个仿真器,它会使程序的开发变得更加容易。用真正的硬件进行测试是最有价值的,事后看来,我们应该花更多的时间在硬件上进行测试。
【讨论】:
用真正的硬件进行测试是最有价值的,事后看来我们应该花更多的时间在硬件上进行测试。 -------------------------------------- 我必须说,用硬件进行测试也很昂贵。尤其是当你在为火箭写软件的时候……对我来说,我们团队只有一台正在开发的原型机,我只能使用它的一小部分……【参考方案2】:将您的测试套件分成两部分:
第一部分针对真实硬件运行测试。这部分用于构建模型。通过为此编写自动测试,如果您对模型是否正常工作有任何疑问,可以再次运行它们。
第二部分与模型对比。这部分自动运行。
在确保硬件连接正确等之后手动运行第 1 部分。一个好主意是创建一套测试,针对工厂返回的内容运行并运行这些测试两次:一次与工厂这将返回真正的“驱动程序”,并且一旦针对您的模拟对象的工厂。这样,您可以确保您的模拟与真实的东西完全一样:
class YourTests extends TestCase
public IDriver getDriver() return new MockDriver ();
public boolean shouldRun () return true;
public void testSomeMethod() throws Exception
if (!shouldRun()) return; // Allows to disable all tests
assertEquals ("1", getDriver().someMethod());
在我的代码中,我通常使用系统属性 (-Dmanual=yes) 来切换手动测试:
class HardwareTests extends YourTests
public IDriver getDriver() return new HardwareDriver ();
public boolean shouldRun () return "yes".equals (System.getProperty("manual"));
【讨论】:
【参考方案3】:如果您正在编写软件来处理来自专用硬件的数据,那么您可以合理地为硬件创建替身来测试软件。
如果硬件接口像串行端口这样简单,您可以轻松地使用环回电缆让您的程序与模拟硬件通信。几年前,我在编写软件与信用处理器交谈时使用了这种方法。我的测试应用程序认为我的模拟器是调制解调器和后端处理器。
如果您正在编写 PCI 设备驱动程序或同等级别的软件,那么您可能无法创建软件替代。
将 TDD 应用于此类问题的唯一好方法是,如果您能够使用另一个程序来欺骗硬件的 i/o。例如,我为加油站处理信用卡。在我目前的项目中,我们有一个模拟器,它是连接到一些开关的泵电子设备,以便可以模拟泵的操作(提升手柄、挤压扳机、燃油流量)。完全可以想象,我们可以构建一个由软件控制的模拟器。
或者,根据设备,您可以使用标准测试设备(信号发生器等)为其提供“已知输入”。
请注意,这存在您同时测试硬件和设备驱动程序的问题。不幸的是,这确实是您现阶段唯一的好选择 - 任何模拟硬件都可能与真实设备有很大差异,因此无法进行测试。
【讨论】:
感谢您的信息,是的,我在最后一部分。我一直在与硬件进行 TDD 斗争,因为嘲笑它似乎毫无意义,因为您并没有真正测试硬件。【参考方案4】:在测试套件中包含访问硬件的测试可能不是一个好主意。这种方法的一个问题是,测试只能在连接到这个特殊硬件的机器上运行,这使得作为(夜间)自动构建过程的一部分运行测试变得很困难。
一种解决方案可能是编写一些行为类似于缺少的硬件模块的软件模块,至少从接口的角度来看是这样。在运行您的测试套件时,请访问这些软件模块而不是真实的硬件。
我也喜欢将测试套件分成两部分的想法:
访问真正的硬件,您可以手动运行 访问软件模块的模块,作为自动测试的一部分运行根据我的经验,涉及真实硬件的测试几乎总是需要一些手动交互(例如,插入和拔出某些东西以查看它是否被正确检测到),这使得自动化变得非常困难。好处往往不值得麻烦。
【讨论】:
是的,好点,我将无法在构建机器上设置硬件。但我挣扎的部分是,如果我过多地模拟硬件,我真正测试的是什么?你是怎么处理的?【参考方案5】:巧妙地模拟。
【讨论】:
+1 当我在嵌入式设备上工作时,这是我们采取的路线。 你有我如何做到这一点的任何例子吗?例如,我如何模拟一个基本上是设备驱动程序的东西,我是否编写自己的模拟器来产生可能发生的事件/错误?【参考方案6】:当我在开发机顶盒时,我们有一个工具可以使用 doxygen cmets 从任何 C API 生成模拟。
然后,我们会使用我们希望硬件返回的内容来启动模拟,以便对我们的组件进行单元测试。
因此,在上面的示例中,您将 FrameGrabber_API_IsDeviceAttached 的结果设置为 false,当您的代码调用该函数时,它会返回 false,您可以对其进行测试。
测试的难易程度取决于您的代码当前的结构。
我们用来生成模拟的工具是内部的,所以我帮不了你。但是有一些有希望的谷歌点击: (免责声明 - 我已经使用过其中的任何一个,但希望它们可以对您有所帮助)
http://code.google.com/p/googlemock/ http://www.opensourcetesting.org/unit_c.php http://spin.atomicobject.com/2006/12/29/cmock-ruby-based-mock-tools-for-c只是检查 - 您的代码中是否有直接 ioctl 调用之类的东西?这些总是很难模仿。我们有一个操作系统包装层,我们可以轻松地为其编写模拟,因此对我们来说非常容易。
【讨论】:
【参考方案7】:如果您有模拟器,您可以针对模拟器编写测试并针对硬件运行这些测试。
这么少的细节很难回答问题:-)
【讨论】:
抱歉,我有点含糊。我在问题中提供了更多信息,这有帮助吗?以上是关于如何使用硬件进行 TDD的主要内容,如果未能解决你的问题,请参考以下文章