启用单元测试方法,使其受到保护

时间:2017-07-11 09:40:33

标签: java styles tdd

让我解释一下问题情景。我的任务是修改复杂的函数testFunc(),如下所示。

public String testFunc() {
    String a = func1();
    String b = func2(a);
    String c = func3(b);
    return c;
} 
private String func1(){
    return "hello";
}
private String func2(String p1){
    return "a" + p1;
}
private String func3(String p1){
    return "b" + p1;
}

我修改了testFunc方法并包含了我的逻辑。但作为一名优秀的开发人员,我希望为我编写的额外逻辑编写无条件测试。 但我没有时间也没有耐心来测试整个方法。我希望只测试我添加的逻辑。

 public String testFunc() {
     String a = func1();
     String b = func2(a);
     String c = func3(b);
     String d = func4(c)
     return d;
 }
 protected final String func4(String p1) {
     return "1" + p1;
 }

将func4作为受保护的最终方法使我有意义,以便我可以彻底地对逻辑进行单元测试。或者编码实践不好?

4 个答案:

答案 0 :(得分:2)

我会将其打包为私有,这比受保护更具限制性。如果您已经在项目中使用了Guava,您甚至可以使用@VisibleForTesting注释该方法,以明确您的意图:

@VisibleForTesting final String func4(String p1) {
  //...
}

最后,包私有方法不会暴露给外部世界,也不属于您的API,因此它不会破坏封装。

答案 1 :(得分:2)

这是一种不好的做法。私有/受保护的方法应该通过调用它们的公共方法来测试。通过将访问修饰符更改为package-private,您实际上是将实现细节暴露给其他类,从而减少了封装。

如果结果很难,你应该考虑重新设计公共API。

答案 2 :(得分:0)

更改单元测试方法的可见性不是一个好习惯。

如果您在项目中使用Spring,则可以使用ReflectionTestUtils org.springframework.test.util.ReflectionTestUtils(简化反思)来访问私有方法和属性。

如果您不想使用Spring,那么您必须进行Java反射。

答案 3 :(得分:0)

嗯,我开始说问题中的两句话与我有些矛盾:

  1.   

    但作为一名优秀的开发人员,我希望为我编写的额外逻辑编写单元测试。

    1.   

      但我没有时间也没有耐心来测试整个方法。一世   我希望只测试我添加的逻辑。

    2. 你是一个优秀的开发人员,自上而下做事,或者没有耐心,然后没有什么可以帮助你。

      回答你的问题,揭露不能重复使用的私人方法,这是非常糟糕的做法,因此不是一种好的方法。虽然您所做的更改不能脱离课程的上下文,但您执行了此更改,例如您有:

      class MyClass {
         public String testFunc() {
            String a = func1();
            String b = func2(a);
            String c = func3(b);
            return c;
         } 
         private String func1(){
            return "hello";
         }
         private String func2(String p1){
            return "a" + p1;
         }
         private String func3(String p1){
            return "b" + p1;
         }
      }
      

      因此,有一些可能的方法可以使用新功能扩展此逻辑,例如,您希望decorate初始类具有新功能并在其中添加新功能,例如:

       class MyNewClass extends MyClass{
      
         private MyClass delegate;
      
         public MyNewClass(MyClass delegate) {
             this.delegate = delegate;
         }
      
         public String testFunc() {
            String c = delegate.testFunc();
            return func4(c);
         } 
      
         private final String func4(String p1) {
            return "1" + p1;
         }
      }
      

      现在,您可以通过mocking MyClass实例编写单元测试,并仅检查新添加的逻辑。

      另一种可能的替代方法是将新功能提取到自己的类中,并仅为其编写测试。