如何用硬件做TDD

时间:2009-02-25 11:04:18

标签: tdd hardware

我工作的所有项目都与一块硬件接口,这通常是软件的主要目的。有没有什么方法可以将TDD应用到与硬件配合使用的代码中?

更新:很抱歉我的问题不清楚。

我使用的硬件是一个从相机捕获图像的图像采集卡。然后我处理这些图像,显示它们并将它们保存到磁盘。我可以使用以前捕获的存储在磁盘上的图像模拟捕获图像后发生的所有处理。

但这是我想要测试的与硬件的实际交互。例如,当没有连接相机时,我的软件是否正确应对,它是否正确启动和停止抓取等等。但这与硬件有关,我不知道如何在硬件不存在时测试它或如果我甚至想要这样做?

第二次更新:我也在寻找一些具体的例子,说明人们究竟是如何处理这种情况的。

7 个答案:

答案 0 :(得分:7)

创建一个用于控制硬件的薄层,并使用完整硬件进行系统测试(手动或自动),以确保控制层按预期工作。然后创建一个控制层的伪/模拟实现,它的外部行为就像真实硬件的接口一样,并在为程序的其余部分执行TDD时使用它。


多年前,我正在编写使用SQUID磁力计进行测量的软件。硬件很大,不可移动且昂贵(video),因此无法始终访问硬件。我们有关于与设备通信协议的文档(通过串口),但文档并非100%准确。

对我们非常有帮助的是创建一个软件,该软件监听来自一个串口的数据,记录并将其重定向到另一个串口。然后我们能够找出旧程序(我们正在替换)如何与硬件进行通信,以及对协议进行反向工程。它们被链接成这样的:旧程序< - >虚拟环回串行端口< - >我们的数据记录器< - >实际串行端口< - >硬件

当时我们没有使用TDD。我们考虑过为硬件编写一个仿真器,以便我们可以单独测试程序,但由于我们并不确切知道硬件应该如何工作,因此很难编写一个精确的仿真器,所以最后我们没有做到这一点。如果我们更好地了解硬件,我们可以为它创建一个模拟器,这将使开发程序变得更加容易。使用真实硬件进行测试是最有价值的,事后我们应该花更多时间来测试硬件。

答案 1 :(得分:4)

如果您正在编写软件来处理来自专用硬件的数据,那么您可以合理地为硬件创建替身来测试软件。

如果硬件接口像串口一样简单,您可以轻松使用环回电缆让您的程序与模拟硬件通信。几年前我在编写软件与信用处理器交谈时使用了这种方法。我的测试应用程序认为我的模拟器是调制解调器和后端处理器。

如果您正在编写PCI设备驱动程序或同等级别的软件,那么您可能无法创建软件替身。

将TDD应用于此类问题的唯一好方法是,如果您能够使用其他程序欺骗硬件的i / o。例如,我处理加油站的信用卡处理。在我目前的项目中,我们有一个模拟器,它是连接到某些开关的泵电子设备,可以模拟泵的操作(提升手柄,挤压触发器,燃料流)。可以想象我们可以构建一个可由软件控制的模拟器。

或者,根据设备的不同,您可以使用标准测试设备(信号发生器等)为其提供“已知输入”。

请注意,这会导致您同时测试硬件和设备驱动程序。不幸的是,这真的是你在这个阶段唯一的好选择 - 任何模拟硬件都可能与真正的设备不同,它将无法用于测试。

答案 2 :(得分:4)

将测试套件分成两部分:

  1. 第一部分针对真实硬件运行测试。这部分用于构建模型。通过为此编写自动测试,如果您对模型是否正常工作有任何疑问,可以再次运行它们。

  2. 第二部分针对模型运行。该部分自动运行。

  3. 在确保硬件正确连接等之后,第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 :(得分:2)

包含访问测试套件中硬件的测试可能不是一个好主意。这种方法的一个问题是测试只能在连接到这个特殊硬件的机器上运行,这使得很难将测试称为(夜间)自动构建过程的一部分。

一种解决方案可能是编写一些行为类似于缺少的硬件模块的软件模块,至少从接口的角度来看。运行测试套件时,请访问这些软件模块而不是真实硬件。

我也喜欢将测试套件分成两部分的想法:

  • 访问您手动运行的真实硬件
  • 访问软件模块的一个,它作为自动测试的一部分运行

根据我的经验,涉及真实硬件的测试几乎总是需要一些手动交互(例如,插入和插入某些东西以查看它是否被正确检测到),这使得自动化变得非常困难。这些好处往往不值得麻烦。

答案 4 :(得分:1)

聪明地嘲笑。

答案 5 :(得分:1)

当我在机顶盒上工作时,我们有一个工具可以从任何带有doxygen注释的C API生成模拟。

然后,我们会根据我们想要的硬件返回模拟,以便对我们的组件进行单元测试。

因此,在上面的示例中,您将FrameGrabber_API_IsDeviceAttached的结果设置为false,当您的代码调用该函数时,它将返回false并且您可以对其进行测试。

测试的简便程度取决于您当前的代码结构。

我们用来生成模拟的工具是内部的,所以我无法帮助你。但有一些有希望的谷歌打击: (免责声明 - 我已经使用了其中任何一种,但希望它们对你有所帮助)

只是检查 - 你的代码中有直接的ioctl调用吗?那些总是很难嘲笑。我们有一个OS包装层,我们可以很容易地编写模拟,因此对我们来说非常容易。

答案 6 :(得分:0)

如果您有模拟器,您可以针对模拟器编写测试并针对硬件运行这些测试。

很难以如此少的细节回答问题: - )