如何创建不调用底层对象构造函数的 ScalaMock 存根?
How do you create a ScalaMock stub that doesn't call the constructor of the underlying object?
考虑以下示例 Scala class 和单元测试:
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",它是空的,因为我没有向它传递任何东西,因为我想要的只是一个存根,当调用特定方法时 returns 一个特定值。
有没有办法在不尝试调用对象的构造函数的情况下创建存根?为什么这在旧版本中有效?
ScalaMock 使用宏定义生成子类。
该宏在编译器 运行.
期间得到 expanded/evaluated
由于 mock 是子类,因此将调用超类的构造函数 - 无一例外。
您也许可以使用一些 cglib 魔法来解决这个问题,但这不是我熟悉的东西。
所以这在旧的 ScalaMock 版本中可能是可行的,但是这个功能不会很快在当前实现中恢复。
另一种选择是自己实际子类化这个东西并模拟子类
class NotSoBrokenClass extends BrokenClass("")
...
val nsb = mock[NotSoBrokenClass]
...
这在某些情况下有效,但如果构造函数依赖于非最终方法调用,您也会看到有趣的行为(例如 NPE)。
考虑以下示例 Scala class 和单元测试:
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",它是空的,因为我没有向它传递任何东西,因为我想要的只是一个存根,当调用特定方法时 returns 一个特定值。
有没有办法在不尝试调用对象的构造函数的情况下创建存根?为什么这在旧版本中有效?
ScalaMock 使用宏定义生成子类。 该宏在编译器 运行.
期间得到 expanded/evaluated由于 mock 是子类,因此将调用超类的构造函数 - 无一例外。 您也许可以使用一些 cglib 魔法来解决这个问题,但这不是我熟悉的东西。
所以这在旧的 ScalaMock 版本中可能是可行的,但是这个功能不会很快在当前实现中恢复。
另一种选择是自己实际子类化这个东西并模拟子类
class NotSoBrokenClass extends BrokenClass("")
...
val nsb = mock[NotSoBrokenClass]
...
这在某些情况下有效,但如果构造函数依赖于非最终方法调用,您也会看到有趣的行为(例如 NPE)。