junit和java:testing非公共方法

JUnit只会testing我们class上公开的那些方法。 我怎么做那些不是(即私人,受保护)的junittesting?

我可以通过不使用junit来testing它们,但我想知道junit标准方法是什么。

一个关于unit testing的学派认为,你应该只能testing公共方法,因为你只应该对你的公共API进行unit testing,通过这样做,你应该用非公开的方法来覆盖代码。 你的旅费可能会改变; 我发现有时候是这样,有时候不是。

有了这个说法,有两种方法来testing非公开的方法:

  • 你可以通过将你的unit testing放在与他们正在testing的类相同的包中来testing受保护的和包范围的方法。 这是一个相当普遍的做法。
  • 您可以通过创build被testing类的子类来testing另一个包中的unit testing的受保护方法,该类将覆盖您想要testing为公共的方法,并让这些重写的方法使用super关键字调用原始方法。 通常,这个“testing子类”是JUnit TestCase类中的一个内部类,用于testing。 在我看来,这是一个多一点哈克,但我已经做到了。

希望这可以帮助。

与许多unit testing问题一样,testing私有方法实际上是一个变相的devise问题。 与其试图做任何棘手的事情来testing私有方法,当我发现自己希望为私有方法编写testing时,我花一分钟时间问自己:“我该如何devise这个,才能通过公共方法彻底地testing它?”

如果这不起作用,JUnitX允许testing私有方法,尽pipe我相信它仅适用于JUnit 3.8。

当你写一个JUnittesting时,你必须做一个微妙的思维转变:“我现在是我自己class的客户。 这意味着私人是私人的,你只testing客户看到的行为。

如果方法真的应该是私人的,我认为这是一个devise缺陷,只是为了testing的可见性。 你必须能够根据客户所看到的来推断其正确的操作。

自从我写这篇文章以来的三年里,我已经开始用稍微不同的方式来解决这个问题,使用Javareflection。

肮脏的小秘密是,你可以使用reflection来testingJUnit中的私有方法,就像你公开的那样。 你可以testing你的内心的内容,而不是把它们公开给客户。

如果您在相对较less的“公共”入口点下埋藏了大量的逻辑,您可能违反了单一责任原则 。 如果可能的话,你会想将代码重构成多个类,最终导致更多的“公共”方法来testing。

最简单的解决scheme是将JUnittesting放在同一个包(但是不同的目录)中,并为方法使用默认(即包私有)可见性。

另一个更复杂的方法是使用reflection来访问私有方法。

以下是其他人一直在嘲笑你的“可能不应该这样做”的方法。 不过,我认为这样做是有可能的。 以下代码将访问专用字段,但私有方法的代码几乎相同。

public void testPrivateField() throws InterruptedException { Class<ClassWPrivateField> clazz = ClassWPrivateField.class; try { Field privateField = clazz.getDeclaredField("nameOfPrivateField"); privateField.setAccessible(true); // This is the line // do stuff } catch(NoSuchFieldException nsfe) { nsfe.printStackTrace(); fail(); } catch(IllegalAccessException iae) { iae.printStackTrace(); fail(); } } 

我几乎总是在我的Java项目中使用Spring,因此,我的对象是为dependency injection而构build的。 它们往往是在应用程序上下文中组合的相当细致的公共接口实现。 因此,我很less(如果有的话)需要testing私有方法,因为这个类本身足够小,所以它不是问题。

即使在我不使用Spring的时候,我也倾向于采用将小的和简单的对象组装成越来越大的抽象的相同的做法,每个抽象都相对简单,但是被聚合的对象变得复杂。

根据我的经验,需要unit testing私有方法是一个指标,可以(而且应该)简化您正在尝试的方法。

那是,如果你还真的觉得需要:

  • 受保护的方法可以通过子类来testing;
  • 包私有方法可以通过将unit testing放在同一个包中来testing; 和
  • 私有方法可以通过提供例如包私有工厂代理方法来进行unit testing。 不理想,但私人确实意味着私人。

您通常不会testing私有方法,因为它们只能(通常)通过另一种公共方法间接进行testing。 当你正在testing驾驶和私人方法,那么他们通常是“提取方法”重构的结果,并已经通过间接testing。

如果你关心的是用很多逻辑来testing一个私有方法,那么你可以做的最聪明的事情就是用一个公共方法把这个代码移动到另一个类中。 一旦你完成了,使用这个代码的以前的方法可以通过具有由存根或模拟提供的function来简化testing。

这不是真正的答案,更多的是我遇到了同样的问题,“如果它需要是私人的,它可能应该被重构”不坐在我的权利。

假设你有一些你想要以某种方式分离出来的function。 例如,假设我有这样的东西:

 public class HolderOfSomeStrings{ private List<String> internal_values; public List<String> get() { List<String> out = new ArrayList<String>(); for (String s:internal_values) { out.add(process(s)); } return get; } private static String process(String input) { //do something complicated here that other classes shouldn't be interested in } } 

这里的要点是,junit迫使我公开或至less保护过程,或把它放在自己的实用阶级。 但是,如果这是HolderOfSomeStrings的某种内部逻辑,那么我认为这是不正确的 – 在我看来,这应该是私人的,并且使得它在某种程度上更加可视化了代码。

借用Andy Hunt的一个想法,即使你的私有方法也必须有一些你感兴趣的副作用。换句话说,它们必须被某种公共方法调用,并执行一个有趣的任务,使得对象状态改变。 testing该状态的变化。

假设你有公共方法pubMethod和私有方法privMethod。 当你调用pubMethod时,它又调用privMethod执行一个任务(也许parsing一个string)。 pubMethod然后使用这个parsing的string以某种方式设置成员variables的值或者影响它自己的返回值。 通过观察对pubMethod的返回值或成员variables(可能通过使用访问器来获取)的期望效果进行testing。

DP4jjar子

为了testing私有方法,我们需要使用reflection,并指出所有的答案。

那么现在这个任务被Dp4j jar的帮助简化了。

  • Dp4j会分析您的代码并自动为您生成Reflection API代码。

  • 只需将dp4j.jar添加到您的CLASSPATH即可。

  • Dp4j.jar包含注释处理程序,他们将在您的代码中查找使用@Test JUnit注释进行注释的方法。

  • Dp4j分析这些方法的代码,如果它发现你是非法访问私有方法,它将用等效的代码replace你的无效的私有方法引用,使用Java的Reflection API。

在这里获取更多细节

您可以使用TestNG而不是JUnit,它不关心私有或公共方法。

如上所述使用reflection来testing私有方法。 如果我们正在跟踪TDD,我们应该testing私有方法,因为TDD意味着稍后不会有任何意外。 所以,人们不应该等待完成他的公开方法来testing私人。 这有助于在重新分解时进行更细粒度的回归testing。

寻找“PrivateAccessor.invoke”。 我的代码从“junitx.util”导入,但我不知道它来自哪里。

几乎每一个post都同意 – 你可能应该重构,除非通过公开testing,否则只是想增加一种不同的方式来考虑它。

把你的class级本身想象成一个“单位”,而不是一个方法。 你正在testing这个类,并且它可以维护一个有效的状态,而不pipe它是如何调用公共方法的。

调用私有方法可能会破坏封装并实际上使testing无效。

作为这种分支的一种,我不确定每个人在整个“多语种编程”问题上都陷入了困境,但是Groovytesting可以在Junit中运行,而忽略了整个公共/非公共问题。 附注中,它被正式分类为“bug”,但是当他们试图修复它的时候,就有这样一个风暴,它就像原来那样被放回原处。

我绝对同意@duffymo代码应该从客户的angular度进行testing(尽pipe他说他放弃了这种思路)。 但从这个angular度来看,私人与其他人有不同的含义。 私有方法的客户端是类本身,所以我更喜欢通过外部(公共/包保护)APItesting它们。 但是,受保护的和包裹保护的成员在那里是为了外部客户,所以我testing他们的假货,inheritance自己的类或者驻留在同一个包中。