如何在Scala中测试私有类方法?

gdi*_*azc 34 testing scala scalatest

我有一个私有方法的伴侣对象,如下所示:

package com.example.people

class Person(val age: Int)

object Person {
  private def transform(p: Person): Person = new Person(p.age + 1)
}
Run Code Online (Sandbox Code Playgroud)

我想测试这个方法,例如:

class PersonSpec extends FlatSpec {

  "A Person" should "transform correctly" in {
    val p1 = new Person(1)
    val p2 = Person.transform(p1) // doesn't compile, because transform is private!
    assert( p2 === new Person(2) )
  }

}
Run Code Online (Sandbox Code Playgroud)

有关测试代码访问私有方法的任何帮助吗?

实际上,正如它所写,我可能能够创建一个子类Person,但如果Person被声明为finalsealed

谢谢!

jle*_*ler 60

在测试一切时,我处于中间位置.我通常不测试所有内容,但有时能够对私有函数进行单元测试而不必破坏我的代码以使其成为可能是非常有用的.如果您使用的是ScalaTest,则可以使用PrivateMethodTester来执行此操作.

import org.scalatest.{ FlatSpec, PrivateMethodTester }

class PersonSpec extends FlatSpec with PrivateMethodTester {

  "A Person" should "transform correctly" in {
      val p1 = new Person(1)
      val transform = PrivateMethod[Person]('transform)
      assert(p2 === invokePrivate transform(p1))
    }
  }
Run Code Online (Sandbox Code Playgroud)

这可能不是你想要做的,但你明白了.

  • `import org.scalatest.{FlatSpec,PrivateMethodTester}`是导入.我讨厌不得不追捕那个废话,然后我忘了把它放在答案中. (8认同)
  • 代码对我不起作用,直到我意识到我应该在`invokePrivate`之前添加类名,即`Person invokePrivate transform(p1))` (4认同)
  • 如何为“对象”做同样的事情? (2认同)

vpt*_*ron 29

您可以将您的方法声明为包私有:

private[people] def transform(p: Person): Person = new Person(p.age + 1)
Run Code Online (Sandbox Code Playgroud)

如果您将PersonSpec放在同一个包中,它将能够访问它.

我留给你来决定单元测试一个私有方法是否真的明智:)

  • 如果问题是"我应该测试私有方法吗?"这是真的.在这种情况下,OP根据许多人发现错误的前提提出了一个真正的技术问题,并且公平地指出这一点.毕竟,解决问题的最佳方法是防止它发生.我还要指出[这个SO线程在同一主题上](http://stackoverflow.com/questions/34571/whats-the-proper-way-to-test-a-class-with-private-methods-using -junit)被认为是如此有价值,它被归档为繁荣.所以这种讨论有先例. (3认同)
  • 技术上当然是正确的,但我认为扩大访问权限的唯一目的是使测试更容易(而不是满足客户的需求)是一个坏主意,暗示有些不对劲.从这个意义上讲,我更接近@Peter的设计气味位置. (2认同)

Pet*_*ler 8

对私有方法进行单元测试的需求是一种设计气味.

要么通过公共API测试它们,如果它们很小并且只是辅助方法就可以了 - 或者,更可能的是,它包含不同的逻辑/责任,应该移动到Person中委托使用的另一个类.然后,您将首先测试该类的公共API.

有关详细信息,请参阅相关答案.

可能你可以使用Java/Scala反射来访问它,但它只是设计问题的一种解决方法.不过,如果需要,请参阅相关的Java答案如何做到这一点.

  • 如果你没有测试你的私有方法,我认为这是代码味道.单元测试应测试应用程序中的最小工作单元.您所描述的更多是针对API的验收测试.您不必通过公共API来测试您的私有方法. (46认同)
  • 在更改代码的过程中,单元测试对开发人员很有用.帮助您的信息不是聚合的通过/未通过条件冒泡到更高级别的API,而是帮助您理解的信息,同时更改**方法完全是**方法的本地,这应该是什么在测试中.虽然"只是在公共API中测试它"对于泡沫化的聚合业务问题是好的,但对于日常开发和密集的代码更改来说并不是很好.反馈循环对于为什么私有方法中的局部更改破坏了测试的原因过于缺乏信息. (3认同)