0

我正在工作的系统(幸运的是)已经有 JUnit 单元测试,它覆盖了一定比例的代码功能(我想总比没有好)。

系统中的方法相互高度依赖,可以作为输入发送到方法的参数组合非常庞大。让我们看一个例子:

public void showMessage (final Language language, final Applications apps, final UserID userId)

根据不同的应用程序和用户 ID,上述方法可以弹出超过 300,000 个不同的消息框。除了对一个方法施加如此巨大的压力至少对其中的几个方法听起来是否合理(IMO 在设计方面不能证明是合理的)这一事实之外,我们还担心会导致巨大问题的错误。

话虽如此,我们发现的内容如下:

  1. 重构 JUnit 单元测试
  2. 提取方法中的很多对象作为参数
  3. 创建对象工厂
  4. 使用工厂创建的不同输入来提供单元测试(可能是蛮力测试?)
  5. 检查新重构的测试的结果

所以基本上,问题如下:

在单元测试之上创建集成测试:可能性和挑战?这是一种定制方法还是一种合理的标准方法?在项目文件和项目构建生命周期中将此类测试放在哪里,是否应该一直构建它们以完成构建过程?

来自 JUnit 实现限制和设计/创意限制的任何类型的反馈/评论。

4

2 回答 2

2

集成测试的重点是验证组件是否正确交互在一起。您的每个单元测试都应该验证单个原子代码。一般经验法则(根据我的经验)如果您有一个超过 10 行代码的单元测试,那么您做错了什么,这当然不包括技术上属于@Before/@After块中测试的一部分的代码。关于单元测试的另一件事是它们可以依赖于任何其他集成测试。我不会使用您上面描述的方法,因为单元测试将使用静态数据。这在回归测试中也起着很大的作用,在回归测试中,旧的单元测试会转移到在发布之前执行的回归套件中。

您的集成测试将依赖于诸如 DBUnit、Selenium 等项目。需要诸如数据库或 GUI 之类的依赖项来执行/验证。单元测试应该在开发人员执行签入之前运行。集成测试应该在每次发生变化时运行(或者无论你对潜在错误的容忍度如何,一天一次太少了)。

我再次建议不要在单元测试中使用动态数据。主要是因为您的断言可能会失败,但这并不能证明单元测试无效。

更新

好吧,正如我所说,我认为这是一个集成测试。我不确定的是,在集成测试中,您正在测试系统链,而不是这些系统的单元测试!单元测试和集成测试之间的依赖性也是一个问题,IMO!

回复:
您对单元测试副集成测试有一个根本的误解。代码单元,即函数没有任何依赖关系,如果它们这样做,您的架构需要进行彻底的检修。通过集成测试,您必须构建不同的场景来证明两个不相交的模块相互交互。这并不意味着将来自两个单元测试的逻辑组合成一个“集成”测试。

于 2012-11-08T16:39:53.237 回答
0

阿米尔,

构建“在单元测试之上的集成测试”是什么意思?我会看到集成测试是相当粗粒度的黑盒测试,测试部署在服务器上与真实数据库、JMS 队列、第 3 方 Web 服务等对话的应用程序。通常,您可能想要模拟您不拥有的基础设施(例如3rd 方网络服务等)。

集成测试将比单元测试慢得多,因此您往往不会在每次构建时都执行它们。如果您使用像 jenkins 这样的 CI 服务器,您可能会创建一个单独的集成构建来执行您拥有的所有测试(单元 + 集成)。

您在单元测试中提到了动态数据。我认为最好使用静态输入数据进行单元测试,以确保它们每次执行时都覆盖相同的执行路径,验证在引入新代码时是否发生任何行为变化或测试一些极端情况......

但..

拥有额外的测试套件也是一个好主意,这些测试会用随机输入数据对您的应用程序施加压力。AFAIK Lucene/Solr 的人采用了这种方法,他们甚至开源了他们自己的随机测试框架。看看这些链接:

http://labs.carrotsearch.com/randomizedtesting.html

http://vimeo.com/32087114

至于如何使用遗留软件的一般方法,我推荐 M. Feather 的“Working Effectively with Legacy Code”。很棒的书,它可能会给你一些想法,如何用单元测试覆盖你现有的代码并提高代码质量。

http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

于 2012-11-19T18:37:23.053 回答