2011-07-03 67 views
2

我想重写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 
    } 
} 

回答

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

+0

谢谢! ScalaTest链接正是我所需要的。 –

-1

这对于依赖注入Scalas语法。

this: <dependency> => 

它的字面意思this特征取决于<dependency>特质。阅读article了解更多信息。

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 = "" 
    } 
    } 
} 

这样的自我型较少侵入。迈克的回答是正确的。这个想法是允许特质叠加,所以你可以混合使用不同的特性,如果你愿意,可以按不同的顺序混合。另一个相关的文章是“可堆叠的特质模式”:

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发生异常,你仍然会得到这种特性的后续行为。 (虽然在这一点上你的套件可能会中止,但在这种情况下可能并不重要,但总的来说这是个好主意。)

+0

执行阅读!然而,有一点让我感到困惑。当使用AbstractSuit特性的Fixture覆盖def时,它必须以抽象为前缀。如上所述,在BeforeAndAfterEach上执行beforeEach覆盖时,不需要“abstract”。为什么区别? –