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

时间:2014-01-26 20:57:55

标签: 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 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被声明为finalsealed会怎样?

谢谢!

8 个答案:

答案 0 :(得分:54)

在测试所有内容时,我处于中间位置。我通常不测试所有内容,但有时能够对私有函数进行单元测试而不必破坏我的代码以使其成为可能是非常有用的。如果您使用的是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))
    }
  }

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

答案 1 :(得分:29)

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

private[people] def transform(p: Person): Person = new Person(p.age + 1)

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

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

答案 2 :(得分:8)

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

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

有关详细信息,请参阅related answer

可能您可以使用Java / Scala反射访问它,但它只是设计问题的解决方法。不过,如果需要,请参阅related Java answer how to do that

答案 3 :(得分:1)

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

Scala实现了功能范例,并通过设计广泛使用了不可变对象,“case classes”就是例子(我认为:Person类应该是一个case类)。

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

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

答案 4 :(得分:1)

@ jlegler在这里的回答对我有所帮助,但在事情发生之前我还有一些调试要做,所以我想我已经准确地写了这里需要的东西。

进行测试:

class A

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

使用:

val theFuncion = PrivateMethod[B]('foo)
val result = A invokePrivate theFunction(c)

注意A,B的位置

答案 5 :(得分:1)

我不认为单元测试是关于测试类的合同 - 它是关于测试简单功能(单元)。

此外,我并不认为将某些方法公开化以使其易于测试是个好主意。我认为尽可能缩小API是帮助其他开发人员使用代码(IDE不会建议私有方法)和理解合同的好方法。

此外,我们不应该将所有内容都放在一个方法中。所以有时我们可以把一些逻辑放到私有方法中....当然我们也想测试它。通过公共API进行测试会增加测试的复杂性。(其他选择是将私有方法的逻辑移动到另一个辅助类并在那里进行测试..这个类不会被开发人员直接使用,也不会混乱api)

我认为,来自大脑的家伙为了某个目的添加了PrivateMethodTester。

答案 6 :(得分:1)

就我个人而言,我说公开所有内容,只是在___前面表示其他开发者不应该使用它。

我意识到这是Scala而不是Python,但无论如何,"We're all consenting adults here."

"私人"方法实际上并不是私有的(for example),当然也不安全,那么为什么要让生活变得更加困难?前置和完成 - 如果另一个开发人员想要在黑暗的地方探索,他们要么有充分的理由要么得到他们得到的东西。

答案 7 :(得分:0)

可能的解决方法是间接测试私有方法:测试调用私有方法的公共方法