[深刻JUnit] 为何别测试private函数

好比说,Bird是咱们要测试的class,它有public, protected,以及private的方法。java

// 文件位置:src/test/sample/Bird.java
package test.sample;
class Bird {
  public void fly() { ... }
  public void eat() { ... }
  protected void singRandomly() { 
    final Song s = findASong(<some_random_number>);
    singASong(s);
  }
  
  private Song findASong() { ... }
  private void singASong() { ... }
}

如今有一个BirdTest class。对这个class而言,它可见的全部函数,是Bird.class.getDeclaredMethods()的返回值。dom

代码细节请看
junit.internal.MethodSorter#getDeclaredMethods()
http://grepcode.com/file/repo1.maven.org/maven2/junit/junit/4.12/org/junit/internal/MethodSorter.java#MethodSorter.getDeclaredMethods%28java.lang.Class%29
以及java.lang.Class#getDeclaredMethods()
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b27/java/lang/Class.java#Class.getDeclaredMethods%28%29maven

全部的public, protected, private方法BirdTest都能看到。可是,看到不等于能调用函数

// 文件位置:tst/test/sample/BirdTest.java
package test.sample;
class BirdTest {
  @Test
  public void testFly_CaseDescription1() {
    ...
    bird.fly(); //固然ok,由于Bird#fly是public的
  }

  @Test
  public void testSingRandomly_CaseDescription1() {
    ... 
    bird.sing(); //ok,由于BirdTest也在test.sample package下面。不然是非法的。
  }

  @Test
  public void testFindASong() {
    ...
    bird.findASong(); // 非法,不能调用Bird的私有函数。
  }
}

在上面的代码里,因为BirdTestBird在一个package test.sample里,因此Bird全部的publicprotected函数,对BirdTest可见。可是,private应该是不可调用的。测试

固然,有人会告诉你如何利用java reflection的API来让private method也能够调用code

// 可有可无的parameter用 '_' 略去了
Method findASong = targetClass.getDeclaredMethod("findASong", _);
findASong.setAccessible(true);
return findASong.invoke(_, _);

可是,这打破了Bird类的封装,是很是很差的。设想,改动private的方法的声明会形成test failure,那么private就失去意义了。与protected其实区别不大。ip

那么应该怎么作呢?get

  • 不去测试private函数,好的private函数都应该是很小很简单的,测试那调用了private函数的public和protected方法便可。it

  • 或者,也许这个private函数其实应该被声明称protected。io

若是以上方法你都以为不合适,而某一个private函数很复杂,很须要测试。那么,根据Single Responsibility原则,这个private函数就应该被放到一个单独的class里面。

class BirdSongs {
  protected Song findASong(Integer id) { ... }
  protected void singASong(Song s) { ... }
}

而后,对BirdSongs#findASong进行测试。

若是您有不一样意见,欢迎与我讨论。

相关文章
相关标签/搜索