4

给定:LegacyControllerClass扩展 a 的A MonsterFrameworkClass(人们只是生活多年的非常令人讨厌的框架的一部分)。框架类做了很多魔术,从默认构造函数中的大量逻辑到反射加载类的静态块。

中的许多生命周期方法LegacyControllerClass,它们会改变全局状态。该execute()方法是一千条线,具有您能想到的所有弊端。

public class LegacyControllerClass extends MonsterFrameworkClass {

   //Life-cycle method
   public void validate(){...}

   //Life-cycle method
   public void preExecute() {...}

   //Life-cycle method
   public void execute() {
       //oodles of legacy code here:
       //    examples: call static methods of 'Util' classes
       //              lots of new X().y(..)
       //              call databases, services
       //              Even call super.execute()!!
       //              More rubbish
       //              More rubbish 
   }
}

好的,现在行动的场景是 execute() 方法。我正在向这些穷人介绍测试驱动开发,通过测试他们称之为“故事”的项目。“故事”涉及向 responseProperties 添加一条错误消息,以便视图(jsp)可以读取并显示它。伪代码类似于:

if (error) {
    Build the error message
    Add the error message into the responseProperties
}

不幸的是,该代码必须在方法中的垃圾之间进行混杂execute()

我的问题是:我能做的最好的事情是什么?我可以提出的解决方案是:

  1. 提取两种方法rubbish1()rubbish2()
  2. 以任何期望在我的测试代码中将它们存根(例如;-设置错误标志)
  3. 将我的代码放在rubbish1()和之间rubbish2()

我开始以这种方式实现它,但这MonsterFrameworkClass确实妨碍了我:比如静态加载、加载ResourceBundle随机属性文件的构造函数魔法等。

是否有替代方法来处理相同的问题?

小小的免责声明:我肯定会购买 Michael Feather 的“Working with Legacy Code”并将其一饮而尽,但 SO 似乎是一个唾手可得的果实。

4

1 回答 1

1

将垃圾重构为方法很好。现在您可以下载 Powermock 来模拟代码中所有可怕的垃圾。完成模拟后,您可以测试您的代码。

如果你不向这个怪物添加任何东西,那就更好了。您可以MonstrosityRubbish通过为新东西编写自己的类来将您的功能组合到(或其他)中。

最重要的是尽可能不要触及任何遗留代码,您可以将代码组合到其中。

所以在代码中:

private MyShinyClass yourShinyObject; // init

public void execute(Param param0) {
    rubbish1();
    yourShinyObject.handleError(param0);
    rubbish2();
}

public class MyShinyClass {

    public void handleError(Param param0) {
        // your code here
    }
}

如果你能设法编写这样的新东西,你将只依赖于Param哪些可以被模拟/存根,并且你的代码可以被测试而不会让你的头发着火。

如果您可以以功能方式编写它,那就更好了,这样您就不必responseProperties在分离的代码中进行操作:

public void execute(Param param0) {
    rubbish1();
    responseProperties.add(yourShinyObject.fetchErrors(param0));
    rubbish2();
}

public class MyShinyClass {

    public List<HopelessError> fetchErrors(Param param0) {
        // your code here
    }
}

当然execute()不需要参数,你可以传递任何你想要的变量/字段handleErrors()

于 2013-10-25T12:01:08.450 回答