如何在 Scala 中测试对象的私有方法

How to test an object's private methods in Scala

我有一个示例对象:

object Foo {
  private def sayFoo = "Foo!"
}

而且我想在没有以下解决方法的情况下测试私有 sayFoo 方法: 1.没有将其定义为包私有 2. 没有将它定义为受保护的,而不是在测试中继承它 class

我看到了一种可能的解决方案,即扩展 privateMethodTester 但它没有 似乎仅适用于 classes.

对象

现在,我知道有些人(如果不是很多)说您不应该测试私有方法,而应该只测试 public 个 (api)。尽管如此,我还是很想测试一下。

感谢进阶

无法通过任何标准方法进行测试。

但是,如果您需要 "cover" 该部分代码,请测试在其实现中使用该私有方法的方法。它是间接的,当然,但它确实有效地测试了代码。

例如,在您的 class 中,您可以使用另一种方法:

def dontSayBar = {
    sayFoo()
    println("Other processing...")
}

如果测试,这将 "cover" 私有方法中的代码。

P.S。一个好的经验法则是,如果您看到 coverage 运行 中没有出现的代码,那么您可能实际上并不需要该代码。

正如其他人所说,没有办法直接测试私有方法,尤其是对象。 但是你可以通过使用反射来绕过限制。

我不确定是否有更简洁的方法可以使用 Scala 反射来做同样的事情 API,但是下面使用 Java 的反射的代码确实有效:

val m = Foo.getClass.getDeclaredMethod("sayFoo")
val inst = Foo.getClass.getField("MODULE$").get()
m.setAccessible(true)
m.invoke(inst)

首先您需要获得对 sayFoo 方法的引用。接下来,您需要获取对保存在 MODULE$ 静态字段中的 Foo 对象的单例实例的引用。

获得两个引用后,您只需要告诉 JVM 从方法中删除访问限制,使其可访问。

这显然是一个丑陋的 hack,但如果谨慎使用并且仅用于测试目的可能会有用。

可能有人已经这样做了:一个注释宏 @Testable 怎么样,它使用公开私有成员的方法发出对象,但仅在编译测试时(否则只是对象)。

scala> object X { private def f = 42 ; def g = 2 * f }
defined object X

scala> X.g
res1: Int = 84

scala> object X { private def f = 42 ; def g = 2 * f ; def testable = new { def f = X.this.f } }
defined object X

scala> X.testable.f
warning: there was one feature warning; re-run with -feature for details
res2: Int = 42

scala> object X { private def f = 42 ; def g = 2 * f ; def testable = new Dynamic { def selectDynamic(name: String) = X.this.f } }
defined object X

scala> X.testable.f
warning: there was one feature warning; re-run with -feature for details
res4: Int = 42

或者,它可以发出不同的 object TestableX