如何验证重构是否等于原始代码

时间:2010-01-26 08:13:44

标签: java validation refactoring

我正在使用遗留的Java代码,没有任何单元测试。为了使用该项目,需要重构许多类。

许多重构都可以用eclipse完成,我是手工做的。经过一些重构后,我回顾了对cvs-HEAD的差异,但我真的不能确定一切都是100%正确的。

问题:如何验证重构,即数学与之前的版本相同?我希望有一个工具,但我也接受“基本的人类算法“作为解决方案。

我知道,“运行你的JUnit-Tests”是最好的答案,但遗憾的是,我的项目中没有任何答案。

谢谢!

10 个答案:

答案 0 :(得分:34)

在“TDD By Example”中有一个特定的部分可以讨论它。问题是您需要单元测试来重构,但复杂的代码通常是不可测试的。因此,您希望重构以使其可测试。周期。

因此,最佳策略如下:

进行微小的重构步骤。当步骤很小时,人们更容易确保整体行为完好无损。仅选择可提高可测试性的重构。这是你的直接目标。不要考虑支持未来的功能(或任何类似的东西)。试想一下“我怎样才能让单元测试能够测试这个方法/类”。

只要方法/类变得可测试,就为它编写单元测试。

重复此过程将逐渐使您进入测试的位置,从而可以更积极地进行重构。通常,这个过程比预期的要短。

答案 1 :(得分:8)

如果您认为可以通过引人注目的程序来检测到这一点,那么您将陷入滑坡。正如其他响应者之一已经说过的那样,两个程序是否相同的问题是不可判定的(通过图灵机)。

如果您没有单元测试,我建议您至少设置一个回归测试工具。拍摄一些输入的快照和程序的一些输出版本1生成/生成,通过版本2运行它并确保结果是相同的。

如果它是一个GUI,我希望它有MVC分离,这样你就可以单独测试模型,否则你可能会卡住。

答案 2 :(得分:5)

  

问题:如何验证a   重构,这是数学的   与之前的版本相同?一世   希望有一个工具,但我也   接受“基本的人类算法”作为   的解决方案。

严格来说,重构是一组众所周知的转换,已被证明可以保留代码的语义。见Refactoring Object-Oriented Frameworks。 其他所有内容都应该被称为重新设计,但我同意两者都可以互换使用。

关于语义保存的推理很难,而且是一个开放的研究课题。例如,请参阅Formalising Behaviour Preserving Program Transformations

直到我们有了检查语义保存的有效工具,确实最好依靠测试。另一种让您对变更更有信心的方法是添加断言合同。它将迫使你进行审查并思考可能发生了什么变化,什么是不变量,什么可以更深入地打破。

答案 3 :(得分:4)

我不敢说没有算法可以验证某个程序在语义上与另一个程序完全相同 - 这有点暂停问题,事实证明这是无法解决的。

另一种稍微自动化的方法是比较两个程序的输出。但是,对于任何大型程序来说都可能很难,因为可能没有明确定义的输入范围......

也许是时候你编写了你发现如此缺乏的单元测试?

编辑:鉴于你接受人类算法 - 这就是我通常所做的。我会研究要重构的代码,并理解它的语义。至少编写一个单元测试,或者对代码库的那一部分进行某种自动化测试。执行重构,然后查看测试是否仍然通过。如果是这样,你很有可能重构(*)没有破坏任何东西。

(*)这里,我的意思是改变实现/算法等的重构,而不仅仅是简单的重命名和改组代码,并将常见的代码行放入方法/基类等等。只要你有很好地理解代码库。

答案 4 :(得分:3)

  

问题:我如何验证重构,这与前一版本的数学相同?我希望有一个工具,但我也接受“基本的人类算法”作为解决方案。

我同意Chii的说法,这本质上是不可能的。如果你真的需要重构它(而不是为遗留代码编写适配器,使你的新东西松散地耦合到旧代码),你必须特别注意子类,重写方法等。编写单元测试可能会有所帮助,但是如果你实际上不知道代码应该做什么,你怎么能为它编写单元测试?您只能编写单元测试以确保新代码执行您认为旧代码所执行的操作。

答案 5 :(得分:2)

我仍然会说“运行你的单元测试”;)。您必须确保结果相同的唯一选择是单元测试。您可以在重构特定代码之前自己添加它们。在开始时需要更长的时间,但从长远来看会节省很多时间。

答案 6 :(得分:1)

我已经完成了以下项目,其中包含一些需要重构的巨大神类:

使用AOP在方法开始时和结束时“转储”对象状态和参数。转储返回值。

然后使用您需要更改的代码记录许多场景,并使用重构代码重播它们。

这不是数学的,设置起来有点沉重,但是在你得到一套很好的非回归测试之后。

使用XStream等工具轻松设置转储器。

答案 7 :(得分:1)

我会选择Itay的答案,但只是给出了另一种选择 如果您愿意为此付费,那么 Agitar 的产品会自动为现有代码生成JUnit测试。这些测试是“特征化”测试,旨在测试代码执行它目前的工作。然后,一旦你做出改变,你就可以看到你想要改变的是什么。

有更多信息here

答案 8 :(得分:1)

理论上,您可以定义一组安全转换(重构),并创建一个程序来检查程序B是将这些重构的有限子集应用于程序A的结果。(通过设置一个避免停止问题上限)。但是我担心制作这样的程序比编写程序A的单元测试困难得多,这是你应该做的。

答案 9 :(得分:1)

我有点惊讶到目前为止还没有人提到迈克尔·费瑟斯的书Working Effectively with Legacy Code。它以各种语言处理这种确切的情况,提供大量实用建议。我推荐给处理遗留项目的任何人。