如何在 Scala 中测试对象的私有方法
Posted
技术标签:
【中文标题】如何在 Scala 中测试对象的私有方法【英文标题】:How to test an object's private methods in Scala 【发布时间】:2016-01-27 08:17:36 【问题描述】:我有一个示例对象:
object Foo
private def sayFoo = "Foo!"
我想在没有以下解决方法的情况下测试私有 sayFoo 方法: 1.不定义为包私有 2. 没有将其定义为受保护,而是在测试类中继承它
我看到了一种可能的解决方案,即扩展 privateMethodTester,但它没有 似乎只适用于类。
现在,我知道有些人(如果不是很多)说您不应该测试私有方法,而应该只测试公共方法 (api)。尽管如此,我仍然想测试它们。
感谢高级
【问题讨论】:
scalatest 有一个丑陋的支持:scalatest.org/user_guide/other_goodies#privateMethodTester 【参考方案1】:可能有人已经这样做了:如何使用注释宏 @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
。
【讨论】:
【参考方案2】:正如其他人所说,没有办法直接测试私有方法,尤其是对象。 但是,您可以通过使用反射来作弊以绕过限制。
我不确定是否有更简洁的方法可以使用 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,但如果谨慎使用并且仅用于测试目的可能会有用。
【讨论】:
【参考方案3】:它无法通过任何标准方法进行测试。
但是,如果您需要“覆盖”该部分代码,请测试在其实现中使用该私有方法的方法。它是间接的,被授予的,但它确实有效地测试了代码。
例如,在您的班级中,您可以使用另一种方法:
def dontSayBar =
sayFoo()
println("Other processing...")
如果经过测试,这将“覆盖”私有方法中的代码。
附:一个好的经验法则是,如果您看到 coverage 运行中未显示的代码,那么您可能实际上并不需要该代码。
【讨论】:
我有几种方法,我以下一种方式调用它们,它们都是私有的: ...f(g(h(x))) 其中只有 h 是公共的,因此这个解决方案不会适合,因为我没有办法专门测试 f 例如。 如果你测试 f,那么你也在测试 g 和 h。您在TDD 中编写的测试是为了测试可访问的 API。如果私有方法没有按照您的标准进行测试,那么您将不得不找到一种方法来使用您可公开访问的 API 来运行该代码。如果您没有通过公共 API 遇到该代码,那么它可能不值得坚持。在类的情况下,非私有方法是唯一经过测试的方法。这些测试将涵盖私有方法(如果使用)。如果不是,那么您可能不需要它。 通过反射进行测试(如其他答案中所做的那样)是可能的,但出于复杂性原因,高度不鼓励这样做。通常,如果您达到完整的代码覆盖率但不一定是完整的方法覆盖率,则测试被认为是完整的。以上是关于如何在 Scala 中测试对象的私有方法的主要内容,如果未能解决你的问题,请参考以下文章