代码之家  ›  专栏  ›  技术社区  ›  Matt Warren

如何使用硬件进行TDD

  •  12
  • Matt Warren  · 技术社区  · 15 年前

    我工作的所有项目都与一个硬件接口,这通常是软件的主要目的。有没有什么有效的方法可以将TDD应用于与硬件一起工作的代码?

    更新: 对不起,我的问题不清楚。

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

    但我想测试的是与硬件的实际交互。例如,当没有连接摄像头时,我的软件是否能够正确地工作,它是否能够正确地启动和停止抓取等。但这与硬件是如此紧密相连,我不知道如何在硬件不存在时测试它,或者我是否应该尝试这样做?

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

    7 回复  |  直到 15 年前
        1
  •  4
  •   Aaron Digulla    15 年前

    将测试套件分成两部分:

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

    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")); }
    }
    
        2
  •  7
  •   Esko Luontola    15 年前

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


    几年前,我在写一个用鱿鱼磁力计测量的软件。硬件又大又不可移动又贵( video ,因此不可能总是能够访问硬件。我们有关于与设备通信协议的文档(通过串行端口),但文档不是100%准确。

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

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

        3
  •  4
  •   Michael Kohne    15 年前

    如果您编写的软件是为了从专门的硬件中处理混合数据,那么您可以合理地为硬件创建代理来测试软件。

    如果硬件接口很简单,比如一个串行端口,你可以很容易地使用一个回环电缆让你的程序与模拟硬件对话。几年前,我在编写软件与信贷处理程序对话时使用了这种方法。我的测试应用程序认为我的模拟器是一个调制解调器和一个后端处理器。

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

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

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

    请注意,这有一个问题,即您同时测试硬件和设备驱动程序。不幸的是,这确实是您在这个阶段唯一的好选择——任何模拟硬件都可能与实际设备有足够的不同,以至于无法进行测试。

        4
  •  2
  •   geschema    15 年前

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

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

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

    • 一个访问真正的硬件,您可以手动运行
    • 访问作为自动测试的一部分运行的软件模块的程序。

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

        5
  •  1
  •   adolfojp    15 年前

    嘲弄地模仿

        6
  •  1
  •   Andrew Barrett    15 年前

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

    然后,我们将用我们希望硬件返回的内容来为模拟程序做准备,以便对我们的组件进行单元测试。

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

    测试的容易程度取决于代码当前的结构。

    我们用来生成模拟的工具在内部,所以我不能帮你。但也有一些有希望的谷歌点击: (免责声明-我已经使用过其中任何一种,但希望它们能对您有所帮助)

    只是检查一下-您的代码中是否有类似于直接ioctl调用的东西?那些总是很难模仿。我们有一个操作系统包装层,可以很容易地为其编写模拟,所以对我们来说非常容易。

        7
  •  0
  •   Wouter Lievens    15 年前

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

    很难用这么少的细节回答问题:—)