从Scala中的抽象类创建匿名类-重复代码

时间:2019-01-06 00:50:08

标签: scala playframework specs2

这里是scala noob。

我不理解来自Play应用程序集成测试(Scala)的以下代码:

package workflows.admin

import play.api.test._

class SignInSpec extends PlaySpecification {

  "An activated user" should {
    "be able to sign in to the admin console" in new WithBrowser(webDriver = WebDriverFactory(FIREFOX)) {
      // some matchers here ...
      true
    }
  }
}

据我所知,该示例从抽象类WithBrowser创建了一个新的匿名类,并将其实例化。该实例将接收(命名的)构造函数参数webDriver

问题是,当我查看WithBrowser时,我不明白发生了什么事:

abstract class WithBrowser[WEBDRIVER <: WebDriver](
    val webDriver: WebDriver = WebDriverFactory(Helpers.HTMLUNIT),
    val app: Application = GuiceApplicationBuilder().build(),
    val port: Int = Helpers.testServerPort) extends Around with Scope {

  def this(
    webDriver: Class[WEBDRIVER],
    app: Application,
    port: Int) = this(WebDriverFactory(webDriver), app, port)

  implicit def implicitApp: Application = app
  implicit def implicitPort: Port = port

  lazy val browser: TestBrowser = TestBrowser(webDriver, Some("http://localhost:" + port))

  override def around[T: AsResult](t: => T): Result = {
    try {
      Helpers.running(TestServer(port, app))(AsResult.effectively(t))
    } finally {
      browser.quit()
    }
  }
}

我有两个问题:

  1. WithBrowser是带有类型参数WEBDRIVER的泛型抽象类,但是在示例中未声明类型参数。相反,匿名类的实例使用命名的构造函数参数webDriver接收此信息。类型参数和构造函数参数之间缺少什么链接?
  2. 该示例声明一个代码块(它仅返回true),并且该代码块是测试本身。但是,该代码在匿名类中位于何处? WithBrowser扩展了Around并覆盖了around函数,该函数执行代码块,但是我不明白所生成的匿名类如何将给定的示例代码块移动到around中。

我们非常感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

  1. Scala可以推断类型参数。由于传递的参数的类型都不与类型参数相关,因此将限制要推断的类型,因此scala编译器只会将其推断为类型Nothing

  2. 代码块通常是该类的构造函数,但这是一种特殊情况。 Around类确实扩展了scala.DelayedInit接口。这会将构造函数中的代码重写为delayedInit函数的调用。实际上是构造函数的代码将作为按名称调用参数传递给此函数。该值(实际上包装在org.specs2.execute.Result.resultOrSuccess调用中)是传递给around函数的参数。

像这样想象Around类:

class Around extends DelayedInit {
  def delayedInit(f: => Unit): Unit = around(f)
  def around(f: => Unit): Unit
}

假设您现在将继承周围类:

class Foo extends Around {
  println("Hello World")
}

上面的内容被重写为此:

class Foo extends Around {
  delayedInit(println("Hello World"))
}

如果我的解释不够清楚,或者您想了解更多实施细节:
-这是AroundDelayedInit文档。