ChatGPT解决这个技术问题 Extra ChatGPT

注释以使私有方法仅对测试类公开[重复]

这个问题在这里已经有了答案:如何测试具有私有方法、字段或内部类的类? (58 个回答) 4 年前关闭。

谁有这个共同需求的解决方案。

我的应用程序中有一个类。

有些方法是公开的,因为它们是 api 的一部分,有些是私有的,因为它们供内部使用,使内部流程更具可读性

现在,假设我想编写一个单元测试,或者更像是一个集成测试,它将位于不同的包中,允许调用此方法,但是,我希望不允许正常调用此方法如果您尝试从应用程序本身的类中调用它

所以,我在想类似的事情

public class MyClass {

   public void somePublicMethod() {
    ....
   }

   @PublicForTests
   private void somePrivateMethod() {
    ....
   }
}

上面的注解将私有方法标记为“public for tests”,这意味着,任何在测试中的类都允许编译和运行时...不在测试包下。

有什么想法吗?有这样的注释吗?有一个更好的方法吗?

似乎你编写的单元测试越多,你就越被迫打破你的封装......

为什么不使用反射来访问私有方法?
@Scott 在宣传您自己的节目时,“[Y] 您必须在回答中披露您的隶属关系。” (stackoverflow.com/help/behavior)。不是质疑 Manifold 框架本身,而是你推广它的微妙方式。

N
Naman

常见的方法是使私有方法受保护或包私有,并将该方法的单元测试放在与被测类相同的包中。

Guava 有一个 @VisibleForTesting annotation,但它仅用于文档目的。


如果您使用 FindBugs,我已经为您构建了 a plugin that can actually verify@VisibleForTesting 方法不会在测试类之外使用。
我有一种情况,我的课程不能和我的测试课程都在同一个包中。我所做的不是像您建议的那样“使私有方法受保护或包私有”,而是将其公开,然后使用@VisibleForTesting。文档指出,默认情况下,此注释将自动将生产版本的可见性设置为私有,因此我不确定是否需要使用低于公共的任何内容。我相信这更灵活,并且允许您根据需要将所有单元测试放在一个包中。
@mpellegr 什么工具会根据该注释更改字段的可见性?我检查了 Guava 文档并没有发现任何相关内容,我认为即使 Guava 想要改变它也不会改变它。
Android 也有自己的 @VisibleForTesting annotation,因此如果您尝试在测试之外使用该功能,linter 会警告您。
C
Cygnusx1

如果您的测试覆盖率对测试类中的所有公共方法都很好,那么公共方法调用的私有方法将被自动测试,因为您将断言所有可能的情况。

JUnit Doc 说:

测试私有方法可能表明应该将这些方法移到另一个类中以提高可重用性。但是如果你必须... 如果你使用的是JDK 1.3 或更高版本,你可以借助PrivilegedAccessor 使用反射来颠覆访问控制机制。有关如何使用它的详细信息,read this article.


IMO 在最里面进行测试非常重要,因此其他一些公共方法调用的小型私有方法。您不应该为某些“不相关的”外部公共方法编写测试,并且必须完美地设置所有内容,以便您的内部/私有方法恰到好处。相反,请自行测试内部/私有方法以验证其功能,无论从何处调用它。
我认为这个答案错过了问题的重点:私有方法对于测试它们是不可见的,而是为了访问它们。可能是为了断言某个状态或使用一个难以注入的模拟对象进行初始化。
N
Nathan Hughes

考虑使用接口来公开 API 方法,使用工厂或 DI 来发布对象,以便消费者仅通过接口了解它们。该接口描述了已发布的 API。这样,您可以在实现对象上公开您想要的任何内容,并且它们的使用者只能看到通过接口公开的那些方法。


s
simpatico

dp4j 有您需要的东西。本质上,您所要做的就是将 dp4j 添加到您的类路径中,并且每当使用 @Test(JUnit 的注释)注释的方法调用私有方法时,它将起作用(dp4j 将在编译时注入所需的反射)。您也可以使用 dp4j 的 @TestPrivates 注释更明确。

如果您坚持还要注释您的私有方法,您可以使用 Google 的 @VisibleForTesting 注释。


我的卡巴斯基在访问此页面时立即触发。有问题的脚本是 xpjxpj8.js 我既没有专业知识也没有时间确认或否认这一点。请谨慎行事。
使用此链接:github.com/gk2go/dp4j
S
Stan Kurilin

或者您可以将此方法提取到某个策略对象。在这种情况下,您可以轻松测试提取的类,并且不要公开方法或使用反射/字节码进行一些魔术。


A
Atreys

关于 Testing Private Methods 的一篇文章列出了一些测试私有代码的方法。使用反射给程序员带来了额外的负担,要记住如果重构完成,字符串不会自动更改,但我认为这是最干净的方法。


f
facundofarias

好的,所以这里我们有两件事正在混合。首先,当您需要标记仅用于测试的东西时,我同意@JB Nizet,使用番石榴注释会很好。

另一件事是测试私有方法。为什么要从外部测试私有方法?我的意思是.. 你应该能够通过他们的公共方法测试对象,最后测试它的行为。至少,我们正在做并尝试向初级开发人员教授,他们总是尝试测试私有方法(作为一种好的做法)。


我发现一个强大的意识形态是在可能的逻辑上使用引用透明的方法,并在它们周围包装不纯的方法来传递参数/对结果做一些事情。就集成测试而言,确实应该测试公共包装方法。然而,通过单元测试,测试那些纯私有逻辑方法更有意义。 Mocking是一种解决方案,但它是IMO更丑的解决方案,只是直接测试逻辑
C
Community

我不知道有任何此类注释,但以下内容可能有价值:unit testing private methods
或以下内容:JMockit


J
Joeri Hendrickx

你不能这样做,从那以后你怎么能编译你的测试呢?编译器不会考虑注释。

对此有两种通用方法

第一个是无论如何都要使用反射来访问方法

第二种是使用包私有而不是私有,然后将您的测试放在同一个包中(但在不同的模块中)。它们本质上对其他代码是私有的,但您的测试仍然可以访问它们。

当然,如果您进行黑盒测试,则无论如何都不应该访问私有成员。


你能举个例子吗?
S
Snicolas

我们最近发布了一个库,它对通过反射访问私有字段、方法和内部类有很大帮助: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 类。


C
Community

据我所知,没有这样的注释。最好的方法是像其他人建议的那样使用反射。看看这个帖子:
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 注释,但这是一个好主意。

干杯!


R
Roger Keays

我只是将测试放在类本身中,使其成为内部类:https://rogerkeays.com/how-to-unit-test-private-methods