这个问题在这里已经有了答案:如何测试具有私有方法、字段或内部类的类? (58 个回答) 4 年前关闭。
谁有这个共同需求的解决方案。
我的应用程序中有一个类。
有些方法是公开的,因为它们是 api 的一部分,有些是私有的,因为它们供内部使用,使内部流程更具可读性
现在,假设我想编写一个单元测试,或者更像是一个集成测试,它将位于不同的包中,允许调用此方法,但是,我希望不允许正常调用此方法如果您尝试从应用程序本身的类中调用它
所以,我在想类似的事情
public class MyClass {
public void somePublicMethod() {
....
}
@PublicForTests
private void somePrivateMethod() {
....
}
}
上面的注解将私有方法标记为“public for tests”,这意味着,任何在测试中的类都允许编译和运行时...不在测试包下。
有什么想法吗?有这样的注释吗?有一个更好的方法吗?
似乎你编写的单元测试越多,你就越被迫打破你的封装......
如果您的测试覆盖率对测试类中的所有公共方法都很好,那么公共方法调用的私有方法将被自动测试,因为您将断言所有可能的情况。
JUnit Doc 说:
测试私有方法可能表明应该将这些方法移到另一个类中以提高可重用性。但是如果你必须... 如果你使用的是JDK 1.3 或更高版本,你可以借助PrivilegedAccessor 使用反射来颠覆访问控制机制。有关如何使用它的详细信息,read this article.
考虑使用接口来公开 API 方法,使用工厂或 DI 来发布对象,以便消费者仅通过接口了解它们。该接口描述了已发布的 API。这样,您可以在实现对象上公开您想要的任何内容,并且它们的使用者只能看到通过接口公开的那些方法。
dp4j 有您需要的东西。本质上,您所要做的就是将 dp4j 添加到您的类路径中,并且每当使用 @Test(JUnit 的注释)注释的方法调用私有方法时,它将起作用(dp4j 将在编译时注入所需的反射)。您也可以使用 dp4j 的 @TestPrivates 注释更明确。
如果您坚持还要注释您的私有方法,您可以使用 Google 的 @VisibleForTesting 注释。
或者您可以将此方法提取到某个策略对象。在这种情况下,您可以轻松测试提取的类,并且不要公开方法或使用反射/字节码进行一些魔术。
好的,所以这里我们有两件事正在混合。首先,当您需要标记仅用于测试的东西时,我同意@JB Nizet,使用番石榴注释会很好。
另一件事是测试私有方法。为什么要从外部测试私有方法?我的意思是.. 你应该能够通过他们的公共方法测试对象,最后测试它的行为。至少,我们正在做并尝试向初级开发人员教授,他们总是尝试测试私有方法(作为一种好的做法)。
你不能这样做,从那以后你怎么能编译你的测试呢?编译器不会考虑注释。
对此有两种通用方法
第一个是无论如何都要使用反射来访问方法
第二种是使用包私有而不是私有,然后将您的测试放在同一个包中(但在不同的模块中)。它们本质上对其他代码是私有的,但您的测试仍然可以访问它们。
当然,如果您进行黑盒测试,则无论如何都不应该访问私有成员。
我们最近发布了一个库,它对通过反射访问私有字段、方法和内部类有很大帮助:BoundBox
对于像这样的课程
public class Outer {
private static class Inner {
private int foo() {return 2;}
}
}
它提供了如下语法:
Outer outer = new Outer();
Object inner = BoundBoxOfOuter.boundBox_new_Inner();
new BoundBoxOfOuter.BoundBoxOfInner(inner).foo();
创建 BoundBox 类只需编写 @BoundBox(boundClass=Outer.class)
即可立即生成 BoundBoxOfOuter
类。
据我所知,没有这样的注释。最好的方法是像其他人建议的那样使用反射。看看这个帖子:
How do I test a class that has private methods, fields or inner classes?
您应该只注意测试方法的异常结果。例如:如果您期望 IllegalArgumentException,但您会得到“null” (Class:java.lang.reflect.InvocationTargetException)。
我的一位同事建议在这些情况下使用 powermock framework,但我没有还没有测试过,所以不知道它到底能做什么。虽然我使用了它所基于的 Mockito 框架,而且这也是一个很好的框架(但我认为并不能解决私有方法异常问题)。
尽管有 @PublicForTests 注释,但这是一个好主意。
干杯!
@VisibleForTesting
方法不会在测试类之外使用。