【问题标题】:Java tool for testing private methods?用于测试私有方法的 Java 工具?
【发布时间】:2011-10-27 18:45:09
【问题描述】:

对于测试私有方法的意义有不同的看法,例如herehere。我个人认为这是有道理的,问题是如何正确地做到这一点。 在 C++ 中,您可以使用 #define hack 或创建测试类 friend,在 C# 中有 InternalsVisibleToAttribute,但在 Java 中我们必须使用 reflection 或使它们“对测试可见”和 annotate them as such为了明确意图。两者的缺点应该很明显了。

我认为应该有更好的东西。以

开头
public class Something {
    private int internalSecret() {
        return 43;
    }
}

如果能在测试代码中调用私有方法就好了

@MakeVisibleForTesting Something something = new Something();
Assert.assertEquals(43, something.internalSecret());

这里的注解将使用反射静默地将所有调用转换为something 的私有方法。我想知道Lombok 是否可以做到(并会询问作者)。

做这么多魔法很可能太复杂了,而且无论如何都需要一些时间,所以我正在寻找一些替代方法。也许用@Decapsulate之类的东西来注释被测类,并使用注释处理器生成一个看起来像Decapsulated_Something的类

public class Decapsulated_Something {
    public Decapsulated_Something(Something delegate) {
        this.delegate = delegate
    }
    public boolean internalSecret() {
        // call "delegate.internalSecret()" using reflection
    }
    ...
}

允许使用

Decapsulated_Something something = new Decapsulated_Something(new Something());
Assert.assertEquals(43, something.internalSecret());

我对注解处理没有太多经验,所以在这里先问一下:

  • 实现起来有多复杂?
  • 我忘记了什么?
  • 您对此有何看法?

【问题讨论】:

  • 你是在问一个工具,还是自己写一个?
  • @Raedwald 我在问如何解决它。绞尽脑汁是一种选择,但并不明确需要重新发明轮子。

标签: java testing reflection private


【解决方案1】:

执行此操作似乎很麻烦。这可能不值得。而是将方法包设为默认值。

但是,如果你确定要调用私有方法,你可以在你的Decapsulated_something 类中使用setAccessible 来允许通过反射调用。所以很简单。

【讨论】:

    【解决方案2】:

    我将回答“一般”问题 :-) 只需几行代码即可通过反射访问方法,并且有相当多的库、实用程序、API 等提供这样做的方法.您可能还可以在自己的代码中使用许多不同的技术。例如字节码操作、反射、类扩展等。但我倾向于保持简单。虽然测试私有方法可能很有用,但您也可能只想测试几个。所以设计复杂的东西可能是矫枉过正。我只是使用已建立的 API,或者编写一个快速方法来访问我感兴趣的私有方法,然后让它完成。

    【讨论】:

      【解决方案3】:

      有多种方法可供选择

      • 不要测试私有方法,因为它们是隐藏的实现细节,永远不会对调用者产生影响。
      • 将方法包设为本地,以便调用者无法访问它们,但您可以在同一个包(即单元测试)中访问它们。
      • 使单元测试成为内部类或提供包本地内部类。不确定这是一种改进!
      • 使用反射访问类的方法。这就像标记一个方法 rpivate 当它不是并且是一个混淆恕我直言。您应该仅在方法真正为私有时才将其标记为私有。

      【讨论】:

        【解决方案4】:

        几年前,我参与了一个项目,该项目生成类以更轻松地对私有方法进行单元测试。 http://java.net/projects/privateer/

        它生成了额外的类,比调用反射更容易,例如如果你有 MyClass.myPrivateMethod() 它会生成一个允许直接调用 myPrivateMethod 的 _MyClass 类。

        它从未真正完成,并且在某些情况下有点用处,但总的来说,除非绝对必要,否则我不建议测试私有方法。通常将它们重新设计为实用程序类(如果您担心用户使用它们,可以使用包访问)是更好的选择。

        【讨论】:

          【解决方案5】:

          如果能在测试代码中调用私有方法就好了

          @MakeVisibleForTesting Something something = new Something();
          Assert.assertEquals(43, something.internalSecret());
          

          有方法注解之类的,看看dp4j@TestPrivates

          @Test
          @TestPrivates 
          //since the method is annotated with JUnit's @Test this annotation is redundant. 
          // You just need to have dp4j on the classpath.
              public void somethingTest(){
                Something something = new Something();
                int sthSecret = something.internalSecret();
                 Assert.assertEquals(43, sthSecret); //cannot use something.internalSecret() directly because of bug [dp4j-13][2] 
              }
          

          【讨论】:

            猜你喜欢
            • 2015-03-14
            • 2017-07-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-05-29
            • 1970-01-01
            • 1970-01-01
            • 2012-04-07
            相关资源
            最近更新 更多