覆盖特质和自我类型

时间:2011-07-03 18:22:33

标签: scala traits scalatest self-type

我想覆盖ScalaTest特性BeforeAndAfterEach,以便为我的所有测试实现一次。最后我把它编译好了,但我不明白为什么。

trait MySetup extends BeforeAndAfterEach {
  this : org.scalatest.BeforeAndAfterEach with org.scalatest.Suite =>
  var service: String = _

  abstract override def beforeEach(): Unit = {
    service = "apa"
    super.beforeEach()
  }

  abstract override def afterEach(): Unit = {
    service = ""
  }
}

让它发挥作用的是行:

  this : org.scalatest.BeforeAndAfterEach with org.scalatest.Suite =>

我在BeforeAndAfterEach实现的开头找到它并将其复制。

它做了什么,为什么需要它呢?

更新

这是一个更简单的版本。

trait MySetup extends FlatSpec with BeforeAndAfterEach {
  var service: String = _

  override def beforeEach {
    service = "apa"
    super.beforeEach
  }

  override def afterEach {
    service = ""
    super.afterEach
  }
}

3 个答案:

答案 0 :(得分:5)

BeforeAndAfterEach具有自我类型的套件,这意味着BeforeAndAfterEach只能混合到扩展套件的类型中。 ScalaTest希望您首先选择主套件类型,然后再选择混合行为。

自我类型声明不会在子特征中继承,因此您必须重新声明自我类型。

以下问题在自我类型和子特征之间存在一些权衡:What is the difference between self-types and trait subclasses?

有关ScalaTest设计的一些背景信息,请参阅:http://www.artima.com/scalazine/articles/selfless_trait_pattern.html

答案 1 :(得分:1)

我可能写MySetup的方式是:

import org.scalatest.Suite
import org.scalatest.BeforeAndAfterEach

trait MySetup extends BeforeAndAfterEach { this: Suite =>

  var service: String = _

  abstract override def beforeEach(): Unit = {
    service = "apa"
    super.beforeEach()
  }

  abstract override def afterEach(): Unit = {

    try {
      super.afterEach() // To be stackable, must call super.afterEach
    }
    finally {
      service = ""
    }
  }
}

这样自我类型就不那么具有侵入性了。迈克的回答是正确的。这个想法是允许特征堆叠,所以如果你愿意,你可以按照不同的顺序混合这样的多个特征。另一篇相关文章是“Stackable Trait Pattern”:

http://www.artima.com/scalazine/articles/stackable_trait_pattern.html

您也可以在相关的Scaladoc部分中找到有用的示例:

http://www.scalatest.org/scaladoc-1.6.1/org/scalatest/FlatSpec.html#composingFixtures

注意我也打电话给super.afterEach。要成为可堆叠的,你需要在beforeEach和afterEach之间调用super。我在尝试中这样做,以便如果super.afterEach因异常而爆炸,你仍然可以获得此特征的后续行为。 (虽然你的套件可能会在那时中止,所以在这种情况下它可能并不重要。但总的来说这是一个好主意。)

答案 2 :(得分:-1)

这是依赖注入的Scalas语法。

this: <dependency> =>

这意味着字面上this特质取决于<dependency>特征。请阅读此article了解更多信息。