单元测试具有不可预测的外部依赖性的代码

时间:2011-11-02 13:03:56

标签: java junit robotics

我参与了一个项目,除其他外,必须控制各种实验室仪器(机器人,读者等......)

这些仪器中的大多数都是通过基于DCOM的驱动程序,串行端口或通过启动具有各种参数的专有程序来控制的。其中一些程序或驱动程序包括模拟模式,有些则不包括。显然,我的开发计算机无法连接到所有仪器,虽然我可以为驱动程序包含模拟模式的仪器启动虚拟机,但是如果没有实际的仪器,有些东西是无法测试的。

现在,我自己的代码主要不是关于仪器的实际操作,而是关于启动操作,确保一切正常,以及在它们之间进行同步。它是用Java编写的,使用各种库与仪器及其驱动程序连接。

我想为各种仪器控制模块编写单元测试。但是,因为仪器可以在很多方面失败(其中一些是记录的,其中一些不是),因为代码依赖于这些部分随机输出,我对于如何为这些部分编写单元测试有点迷失。我的代码。我考虑过以下解决方案:

  • 仅测试连接的实际仪器,可能是最准确的方法,但它根本不实用(在读卡器中插入板,运行单元测试,移除板,运行单元测试等等),更不用说潜在的了危险的,
  • 使用模拟对象来模拟与事物实际通信的部分;虽然这个肯定更容易实现(和运行),但它可能无法重现各种潜在的失败(如上所述,很多都是未记录的,有时会导致不良意外)。

虽然我现在正考虑与后者合作,但我错过了什么?有更好的方法吗?

3 个答案:

答案 0 :(得分:6)

您的两个要点都是有效的选项,但它们分别代表两种不同的测试。

在非常高的层次上,使用Mock对象(按照你的第二个项目符号点)非常适合单元测试 - 它只是测试你的代码(测试中的系统或SUT),没有任何其他内容。 。任何其他依赖项都被模拟出来。然后,您可以编写测试用例以抛出尽可能多的不同错误条件(当然也可以测试“快乐路径”)。您的错误条件域未记录的事实是不幸的,并且您应该努力尽可能地减少错误。每次使用实际的外部设备遇到新的错误情况时,您应该弄清楚如何通过代码重现它,然后编写另一个新的单元测试,通过模拟框架重新创建该条件。

此外,使用连接的实际仪器(按照您的第一个项目符号点)进行测试对于集成测试非常有用 - 它可以更好地测试您的代码以及实际的外部依赖性。

一般情况下,单元测试应该很快(理想情况下,在10分钟内编译代码并运行整个单元测试套件。)这意味着如果您有任何新代码,您将从单元测试中快速获得反馈。写了导致任何测试失败。集成测试本质上可能需要更长时间(例如,如果您的一个外部设备需要1分钟来计算结果或执行任务,并且您正在测试15种不同的输入,那么15分钟就可以了有一小组测试。)你的CI服务器(你应该有一个自动编译和运行所有测试的服务器)应该在提交到源控制存储库时自动触发。它应该编译并运行单元测试作为一步。在完成该部分之后,它应该为您提供反馈(好的或坏的),然后如果单元测试全部通过,它应该自动启动您的集成测试。这假设有一个实际设备连接到您的CI服务器,或者是一个合适的替代品(无论在您的特定环境中是什么意思。)

希望有所帮助。

答案 1 :(得分:4)

如果你正在使用模拟,那么你可以用不同的模拟代替不同的模拟。也就是说,您的测试将是一致的。这是有价值的,因为对随机执行的系统运行测试不会给你一种安全感。每次运行都可以/将执行不同的代码路径。

由于您事先并不知道所有故障情况,我认为有两种(非独占)方案:

  1. 在您看到这些故障时捕获这些故障的详细信息,并在您的模拟中编码进一步的测试以复制这些故障。因此,您的日志记录需要合理,以捕获故障详细信息。随着时间的推移,您的测试集将扩展到包含并回归测试这些场景。
  2. 您与这些系统的接口可能能够捕获所有错误,但会将它们呈现在有限的错误子集中。例如将所有错误归类为(比如)连接错误,超时等。这样您就可以将场景限制为一小组失败。不幸的是,我不知道这对你的申请是否实用。

答案 2 :(得分:3)

根据定义,您无法对未预期的内容进行单元测试。

第二种方法适用于单元测试。连接实际仪器使其充其量进行集成测试。

拆分依赖关系,以便您可以创建一个虚假的工具,然后以尽可能多的方式模拟现实。随着您对现实的理解的提高,更新您的假货并添加测试以应对这种情况。 (在某些情况下,模拟可能是适当的,在其他情况下也是伪造的。)