3

考虑以下示例 Scala 类和单元测试:

class BrokenClass(s: String) {
  private val len = s.length
  def length(): Int = len
}

class BrokenTest extends FlatSpec with Matchers with MockFactory {

  "A BrokenClass" should "stub correctly" in {
    val stubThing = stub[BrokenClass]
    (stubThing.length _) when () returns (10)
    stubThing.length should equal (10)
  }

}

在旧版本的 ScalaMock 中,此代码可以工作。使用 Scala 2.12 和 ScalaMock 3.6,我得到了 NullPointerException,因为即使我正在创建一个存根,它仍在调用 BrokenClass 构造函数的“s.length”行。所以它试图取消引用“s”,它是空的,因为我没有向它传递任何东西,因为我想要的只是一个在调用特定方法时返回特定值的存根。

有没有办法在不尝试调用对象的构造函数的情况下创建存根?为什么这在旧版本中有效?

4

1 回答 1

3

ScalaMock 使用宏定义生成子类。该宏在编译器运行期间得到扩展/评估。

由于模拟是子类,因此将调用超类的构造函数——没有例外。您也许可以使用一些 cglib 巫术来解决这个问题,但这不是我所熟悉的。

所以这可能在旧的 ScalaMock 版本中是可能的,但是这个特性不会很快在当前的实现中恢复。

另一种选择是自己实际子类化这个东西并模拟子类

class NotSoBrokenClass extends BrokenClass("")
...
val nsb = mock[NotSoBrokenClass]
...

这在某些情况下有效,但如果构造函数依赖于非最终方法调用,您也会看到有趣的行为(例如 NPE)。

于 2018-07-13T20:11:14.897 回答