Wordspec "should" "when" "in"
Wordspec "should" "when" "in"
我正在为我的一个 Scala 测试套件初始化一个伴随对象。此伴随对象中的一个字段是延迟评估的,并使用测试套件中的一些字段进行初始化。类似于:
class SomeClassSpec extends WordSpec with Matchers with OneInstancePerTest {
lazy val someFieldTheCompanionObjectNeeds = "some_field_I_need"
"my test class" should {
"do something interesting" when {
"I tell it to" in {
//a bunch of test code using the SomeTestClassCompanionObject.someConfigurationINeed field.
}
}
}
}
object SomeTestClassCompanionObject extends SomeClassSpec {
lazy val someConfigurationINeed = Config(SomeTestClass.someFieldTheCompanionObjectNeeds)
}
别问了。我知道这是不好的做法,但必须这样做,而且这在很大程度上与我的问题无关。
我在这里注意到的是,如果我试图在测试的 when
块中使用它,我的 SomeTestClassCompanionObject.someConfigurationINeed
字段没有被初始化,但是它 是 在 in
块中初始化。我的问题是:究竟是什么区分了 Wordspec 中的 should
、when
、in
范围?我的印象是这些只是逻辑上的差异,但这个测试表明不同的东西在 JVM 代码的底层 "static" 块中的不同时间被初始化。
是否有人有任何进一步的阅读或指向 Wordspec 文档的链接来解释这里发生的事情?
@BogdanVakulenko下面怎么设计
class SomeClassSpec {
SomeTestClassCompanionObject.someConfigurationINeed // NullPointerException or WhosebugError because calling child's constructor which in turn calls parent's constructor
}
object SomeTestClassCompanionObject extends SomeClassSpec {
lazy val someConfigurationINeed = ??
}
失败,因为从父构造函数调用子构造函数会导致循环。这种情况发生在 should
和 when
class SomeClassSpec {
"my test class" should {
SomeTestClassCompanionObject.someConfigurationINeed // error
}
"do something interesting" when {
SomeTestClassCompanionObject.someConfigurationINeed // error
}
}
因为尽管他们采用了 pass-by-name 参数 f
,但仅在使用时才进行评估
def should(right: => Unit)
def when(f: => Unit)
它们导致调用 registerNestedBranch 确实评估 f
从而触发循环
def registerNestedBranch(description: String, childPrefix: Option[String], fun: => Unit, registrationClosedMessageFun: => String, sourceFile: String, methodName: String, stackDepth: Int, adjustment: Int, location: Option[Location], pos: Option[source.Position]): Unit = {
...
try {
fun // Execute the function
}
...
}
另一方面,in
不会出现循环
class SomeClassSpec {
"I tell it to" in {
SomeTestClassCompanionObject.someConfigurationINeed // ok
}
}
也需要 f
by-name
def in(f: => Any /* Assertion */)
因为它会导致调用 registerTest
,它只注册函数值 f
以供执行,但 f
在传递给注册时绝不会被求值。然后单独的 Runner
对象实际运行 f
但此时对 SomeTestClassCompanionObject.someConfigurationINeed
的调用是在 SomeClassSpec
的构造函数之外执行的,因此没有触发循环。
我正在为我的一个 Scala 测试套件初始化一个伴随对象。此伴随对象中的一个字段是延迟评估的,并使用测试套件中的一些字段进行初始化。类似于:
class SomeClassSpec extends WordSpec with Matchers with OneInstancePerTest {
lazy val someFieldTheCompanionObjectNeeds = "some_field_I_need"
"my test class" should {
"do something interesting" when {
"I tell it to" in {
//a bunch of test code using the SomeTestClassCompanionObject.someConfigurationINeed field.
}
}
}
}
object SomeTestClassCompanionObject extends SomeClassSpec {
lazy val someConfigurationINeed = Config(SomeTestClass.someFieldTheCompanionObjectNeeds)
}
别问了。我知道这是不好的做法,但必须这样做,而且这在很大程度上与我的问题无关。
我在这里注意到的是,如果我试图在测试的 when
块中使用它,我的 SomeTestClassCompanionObject.someConfigurationINeed
字段没有被初始化,但是它 是 在 in
块中初始化。我的问题是:究竟是什么区分了 Wordspec 中的 should
、when
、in
范围?我的印象是这些只是逻辑上的差异,但这个测试表明不同的东西在 JVM 代码的底层 "static" 块中的不同时间被初始化。
是否有人有任何进一步的阅读或指向 Wordspec 文档的链接来解释这里发生的事情?
@BogdanVakulenko
class SomeClassSpec {
SomeTestClassCompanionObject.someConfigurationINeed // NullPointerException or WhosebugError because calling child's constructor which in turn calls parent's constructor
}
object SomeTestClassCompanionObject extends SomeClassSpec {
lazy val someConfigurationINeed = ??
}
失败,因为从父构造函数调用子构造函数会导致循环。这种情况发生在 should
和 when
class SomeClassSpec {
"my test class" should {
SomeTestClassCompanionObject.someConfigurationINeed // error
}
"do something interesting" when {
SomeTestClassCompanionObject.someConfigurationINeed // error
}
}
因为尽管他们采用了 pass-by-name 参数 f
,但仅在使用时才进行评估
def should(right: => Unit)
def when(f: => Unit)
它们导致调用 registerNestedBranch 确实评估 f
从而触发循环
def registerNestedBranch(description: String, childPrefix: Option[String], fun: => Unit, registrationClosedMessageFun: => String, sourceFile: String, methodName: String, stackDepth: Int, adjustment: Int, location: Option[Location], pos: Option[source.Position]): Unit = {
...
try {
fun // Execute the function
}
...
}
另一方面,in
class SomeClassSpec {
"I tell it to" in {
SomeTestClassCompanionObject.someConfigurationINeed // ok
}
}
也需要 f
by-name
def in(f: => Any /* Assertion */)
因为它会导致调用 registerTest
,它只注册函数值 f
以供执行,但 f
在传递给注册时绝不会被求值。然后单独的 Runner
对象实际运行 f
但此时对 SomeTestClassCompanionObject.someConfigurationINeed
的调用是在 SomeClassSpec
的构造函数之外执行的,因此没有触发循环。