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

如何在Scala中测试私有类方法?,scala,testing,scalatest,Scala,Testing,Scalatest,我有一个带有私有方法的伴生对象,如下所示: package com.example.people class Person(val age: Int) object Person { private def transform(p: Person): Person = new Person(p.age + 1) } 我想用以下方法测试此方法: class PersonSpec extends FlatSpec { "A Person" should "transform corr

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

package com.example.people

class Person(val age: Int)

object Person {
  private def transform(p: Person): Person = new Person(p.age + 1)
}
我想用以下方法测试此方法:

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) )
  }

}
关于让测试代码访问私有方法有什么帮助吗

实际上,正如所写的,我可能能够创建
Person
的子类,但是如果
Person
被声明为
final
sealed
,该怎么办


谢谢

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

您可以通过公共API对它们进行测试,如果它们很小并且只是帮助器方法,那么就可以了;或者,更可能的情况是,它包含不同的逻辑/职责,应该移动到委托人使用的另一个类。然后首先测试该类的公共API

有关更多详细信息,请参阅


您可能可以使用Java/Scala反射来访问它,但这只是解决设计问题的一种方法。不过,如果需要,请参阅。

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

private[people] def transform(p: Person): Person = new Person(p.age + 1)
如果您将PersonSpec放在同一个包中,它将能够访问它


我让您来决定对私有方法进行单元测试是否真的是明智的:)

一般来说:如果您想有效地测试代码,您必须首先编写可测试的代码

Scala实现了函数范式,并通过设计广泛使用了不可变对象,“案例类”就是示例(我的观点:Person类应该是案例类)


如果对象具有可变状态,则实现私有方法是有意义的,在这种情况下,您可能希望保护对象的状态。但如果对象是不可变的,为什么要将方法实现为私有的呢?在您的示例中,该方法生成Person的副本,您出于什么原因希望将其设置为私有?我看不出有什么理由


我建议你考虑一下。同样,如果你想有效地测试你的代码,你必须把它编写成可测试的。

一个可能的工作是间接测试私有方法:测试一个调用私有方法

< p>的公共方法,在测试一切时,我处于中间。我通常不会测试所有的东西,但有时能够对私有函数进行单元测试而不必修改代码使其成为可能,这真的很有用。如果您使用的是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)
      // We need to prepend the object before invokePrivate to ensure
      // the compiler can find the method with reflection
      assert(p2 === p1 invokePrivate transform(p1))
    }
  }

这可能不是你想做的,但你知道了

@jlegler的回答对我很有帮助,但在一切正常之前,我还需要做一些调试,所以我想我应该在这里写下所需的东西

要测试:

class A

object A {
  private def foo(c: C): B = {...}
}
使用:


注意A,B的位置,我不认为单元测试是关于测试类的契约,而是关于测试简单的功能(单元)

我也不认为公开一些方法只是为了使它们易于测试是一个好主意。我相信,让API尽可能狭窄是帮助其他开发人员使用您的代码(IDE不会建议私有方法)和理解合同的好方法

我们也不应该把一切都放在一个单一的方法中。所以有时候我们可以在私有方法中加入一些逻辑。。。。当然,我们也想测试一下。通过公共API测试它会增加测试的复杂性。(另一个选项是将私有方法的逻辑移动到另一个帮助器类并在那里测试它。.这个类不会被开发人员直接使用,也不会使API变得混乱)


scalatest的人,我想,加入PrivateMethodTester是有目的的

就我个人而言,我建议将一切公开,并在前面加上
\uu
\u
,以表明其他开发人员不应该使用它

我知道这是Scala而不是Python,但不管怎样


“Private”方法实际上不是Private(),当然也不安全,所以为什么要让本质上是社会契约的东西变得更难呢?预先编写并完成——如果另一个开发人员想在黑暗的地方四处窥探,他们要么有很好的理由,要么应该得到他们所得到的。

将其包私有化,将测试代码放在同一个包中的测试根下。单元测试测试测试类是否符合他们的契约。私有方法不是该契约的一部分,也不受类不变量的约束。我认为不应该(直接)测试私有方法。好的,同意。但是假设我有一个复杂的数据结构,
transform
方法在该数据结构上实现了一个特定的算法。我不希望该算法在API中公开,但我需要它在任何情况下都能工作。我应该把
transform
方法放在哪里才能彻底测试它?为什么该算法在API中不可用?为什么不在
Person
中将
transform
作为公共方法?它没有泄露任何算法的抽象。从技术上讲,这当然是正确的,但我认为仅仅为了使测试更容易(而不是满足客户的需求)而扩大访问是一个坏主意,并暗示出一些问题。从这个意义上说,我更接近于@Peter对设计嗅觉的定位。@Vidya SO被设计来主持技术问题/答案,我相信其他stackExchange网站也会主持设计/最佳实践问题。如果问题是“我是否应该测试私有方法?”在这种情况下,OP提出了一个真正的技术性问题,这个问题的前提是很多人都认为是错误的,公平地指出这一点。毕竟,解决问题的最好办法是防止它发生。我还想指出的是,它被认为是如此宝贵,以至于它被存档是为了繁荣。所以这类讨论有一个先例。@Vidya它没有存档,是在So时代早期(2008年)提出的,当时适度性和站点范围不是很严格,所以它是一个不好的优先论据。另请参见2012年发布的帖子中的大量条目,
val theFuncion = PrivateMethod[B]('foo)
val result = A invokePrivate theFunction(c)