2014-06-20 34 views
1

你好我的Java有点生疏,所以请耐心等待。我的任务是减少研究项目中重复代码的数量,因此我认为我无法在此处发布任何代码。但基本上,我有大约20个不同类别的大致相同的方法(测试方法),我一直在尝试两种不同的方法来解决这个问题,但我遇到了每个问题。将变量传递到使用其他方法或继承的方法

我发现,以减少重复第一种方式是,以除去包含在所有的试验方法初始变量并将其放置在一个单独的方法(制备方法)类的超类的内部和具有它称为测试方法。这个解决方案的问题不是在准备方法中声明的所有变量将保持本地状态,并且一旦在另一个方法中调用该方法时就会被擦除?

我的第二个想法是让超类的所有变量字段,并让它们被子类继承。这个解决方案几乎可以工作,除了其中一个变量IFile importedFile = importFile(file);是创建这些变量所必需的变量之一,它必须包含抛出异常所包含的任何内容,我不相信你可以用类来完成。

我一直希望有人能够用这些解决方案之一指出我正确的方向,或者可能会提出另一个我一直无法找到的解决方案。

我忘了提及的一点是,除了初始变量之外,每种测试方法在写入测试方法时略有不同。 编辑:如果不是这样的话,我会把这个方法拉进超类,并且完成它。

编辑:下面是测试方法,我使用了超类的部分,

// method inside of the subclass  
public void test() throws Exception { 
      // variables removed and placed in AbstractTest 
      for (int i = 0; i < expectedExitNodeCount; i++) { 
       if (markerFields.peekFirst().equalsIgnoreCase("EXPOSED_EXIT")) { 
        expectedExitNodes.add(new CTrueExitNode()); 
       } else { 
        fromLine = Integer.parseInt(markerFields.removeFirst().trim()); 
        fromCol = Integer.parseInt(markerFields.removeFirst().trim()); 
        toLine = Integer.parseInt(markerFields.removeFirst().trim()); 
        toCol = Integer.parseInt(markerFields.removeFirst().trim()); 
        length = length(ast, fromLine, fromCol, toLine, toCol); 
        assertTrue(length > 0); 
        ICFlowNode expectedExit = findNode(ast, ICFlowNode.class, fromLine, fromCol, length); 
        assertNotNull(expectedExit); 
        expectedExitNodes.add(expectedExit); 
       } 
      } 
       // additional code omitted from method 
      } 

// Superclass the variables have been placed in. 
public abstract class AbstractTestCase extends WorkTest { 
    protected File file; 
    protected String markerText; 

    public AbstractTestCase(String name, VPG< ? , ? , ? > vpg) { 
     super(name, vpg); 
    } 

    protected void prepare() throws Exception { 
     // Variables used in the test method 
      IFile importedFile = importFile(file); 

     project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); 
     CVPG.getInstance().ensureVPGIsUpToDate(); 

     CTranslationUnit ast = CVPG.getInstance().acquireTransientAST(
      ResourceUtil.getFilenameForIFile(importedFile)); 

     LinkedList<String> markerFields = MarkerUtil.parseMarker(markerText); 

     int fromLine = Integer.parseInt(markerFields.removeFirst().trim()); 
     int fromCol = Integer.parseInt(markerFields.removeFirst().trim()); 
     int toLine = Integer.parseInt(markerFields.removeFirst().trim()); 
     int toCol = Integer.parseInt(markerFields.removeFirst().trim()); 
     int length = length(ast, fromLine, fromCol, toLine, toCol); 
     assertTrue(length > 0); 
     IASTNode node = findNode(ast, IASTNode.class, fromLine, fromCol, length); 
     assertNotNull(node); 

     Integer expectedExitNodeCount = Integer.parseInt(markerFields.removeFirst().trim()); 
     Set<ICFlowNode> expectedExitNodes = new HashSet<ICFlowNode>(); 
    } 

    protected void test() throws Exception { 
     //Considered making test a inherited method 
    } 
} 
+0

你面临的例外是什么? –

+2

这将很难帮助删除无代码的轻微差异的重复。请求权限发布它或提出一个遵循相同模式的假示例。 –

+0

“每种测试方法略有不同”...有时[Template method pattern](http://en.wikipedia.org/wiki/Template_method)可以处理这种性质的重复。 – ajb

回答

0

定义变量作为字段是一个很好的方式,我想。但是你应该稍后初始化它们。只需使用一个构造函数来初始化变量,然后就可以捕获异常!

1

为什么现场方法并不那么酷:您正在引入顺序耦合。接下来谁不会知道,如果没有调用方法准备,方法测试将失败。此外,如果一个类扩展另一个或结构的变化,你可能最终调用准备的两倍,并具有难以跟踪误差

模式1)将所有的变量进入状态对象

组变量进入一个新的对象 - 而不是超类

创建一个生成器对象,这样就可以轻松地初始化类,你需要什么变量到这个对象

更改测试方法来接受这个对象和工作从其数据

public class TestParameters { 
    public boolean flag1; 
    public int someNumber; 
} 

public class Tester { 

    public static void test(TestParameters p) { 
     for (int i=0; int i<p.someNumber;i++) { 
      if (p.flag1) doA(); 
      else doB(); 
     } 
    } 
} 

public class Builder { 
    TestParameters p = new TestParameters(); 

    new Builder() { 
    } 

    public Builder setFlag(boolean f) { 
     p.flag1 = f; 
    } 

    public Builder setNumber(int n) { 
     p.someNumber = n; 
    } 
    public TestParameters build() { 
     return p; 
    } 
} 

public class SomeClass { 

    public void doSomething() { 
     TestParameters p = new Builder().setFlag(true).setNumber(10).build(); 
     Tester.test(p); 
    } 
} 

模式2)控制

反转为您的测试方法的类,使这个新类的可变部分领域。这个类的构造函数中设置变量 - 添加静态getInstanceForXxxx方法和硬编码你需要为每个静态干将的魔法值 - 到每个getInstanceForXxxx您创建一个新的实例传递任何initializarion价值客户需要

public class Tester { 
    public boolean flag1; 
    public int someNumber; 

    private Tester() {}; 

    //feel free to be more descriptive if each initialization apply for more than one class 
    public static Tester testForClassSomeClass() { 
     Tester t = new Tester(); 
     t.flag1=false; 
     t.int=2; 
     return t; 
    } 

    public void test() { 
     for (int i=0; int i<someNumber;i++) { 
      if (flag1) doA(); 
      else doB(); 
     } 
    } 

} 


public class SomeClass { 

    public void doSomething() { 
     Tester t = Tester.testForClassSomeClass(); 
     t.test(); 
    } 
} 

模式3 )在策略中封装行为

创建一个基类。重复代码中的每个点都不同,重构为一个私有方法。创建一个类并用你需要的专门代码覆盖每个方法。实例化正确类为每个客户端,并呼吁公众测试方法

public abstract class Tester { 


    private Tester() {}; 

    public boolean getFlag(); 
    public int getNumber(); 
    public int someLogic(); 

    public void test() {...} 

} 
public class SomeClassTester { 


    private Tester() {}; 


    public int getNumber() { 
     return false; 
    } 
    public int someLogic() { 
     doA(); 
    } 

    public static void test() { 
     for (int i=0; int i<getNumber();i++) { 
      doA(); 
     } 
    } 

} 


public class SomeClass { 

    public void doSomething() { 
     Tester t = new SomeClassTester(); 
     t.test(); 
    } 
} 

我喜欢这最后的,因为它摆脱了标志(FLAG1)和封装正确的行为(具体SomeClass的测试只有DOA()调用)