2011-11-02 44 views
3

我有一个特性,添加了几个测试,并在块之前。具体实例的@Before块在特征中的块之前运行。哎呀,这意味着我不能截断数据库表,然后插入夹具:如何订购@Before方法

trait DatabaseTest { 
    @Before 
    def truncate() { 
    // "TRUNCATE %s".format(tableName) 
    } 

    def tableName 
} 

class PersonasTest extends DatabaseTest { 
    @Before 
    def addPersona() { 
    // "INSERT INTO %s VALUES (...)".format(tableName) 
    } 


    @Test 
    def testRejectsInsertWhenAlreadyInTable() { 
    // "INSERT INTO %s VALUES (...)".format(tableName) 
    } 

    def tableName = "personas" 
} 

testRejectsInsertWhenAlreadyInTable总是成功,因为执行顺序将是:

  • addPersona
  • truncate
  • testRejectsInsertWhenAlreadyInTable

什么是订购@Before块的正确方式,而不会对子类施加太多限制?我总是可以在trait中声明truncate,然后在子类中有一个@Before方法,但是我必须记住让所有的子类调用该截断方法。

在Scala 2.9.0.1上使用JUnit 4.10。

回答

4

这样做的正确方法是使用@Rule,之前和之后的行为类型(在Java语法)延长@ExternalResource

@Rule 
public ExternalResource resource= new ExternalResource() { 
     @Override 
     protected void before() throws Throwable { 
       myServer.connect(); 
     }; 

     @Override 
     protected void after() { 
       myServer.disconnect(); 
     }; 
}; 

你可以链和订单多@Ruleš在一起,以便通过使用@RuleChain(在4.10中引入),又在Java语法:

@Rule 
public TestRule chain= RuleChain 
         .outerRule(new LoggingRule("outer rule") 
         .around(new LoggingRule("middle rule") 
         .around(new LoggingRule("inner rule"); 

有一个警告。你不能在scala中指定一个公共字段(公用字段用访问器方法包装,并且这些字段本身变为私有)。 JUnit检查@Rule是否适用于公共领域。修改JUnit代码,以便您可以将@Rule应用于方法以及字段。

这个问题已经被我修复了,并且已经被合并到了master中,但不幸的是,它还没有发布:它将成为4.11的一部分。所以你有两种选择:使用4.11-SNAPSHOT,或者下载4.10版本并应用patch for @Rule

Scala的代码可能看起来是这样的:

trait DatabaseTest { 
    def truncate(): TestRule = { 
     new ExternalResource() { 
      override def before() = { 
       // "TRUNCATE %s".format(tableName) 
      } 
     } 
    } 

    def extra(): TestRule = { 
     // return a no-op rule 
    } 

    @Rule def testRule() = new RuleChain(truncate(), extra()) 
    def tableName 
} 

class PersonasTest extends DatabaseTest { 
    def extra(): TestRule { 
     new ExternalResource() { 
      override def before() = { 
       // "INSERT INTO %s VALUES (...)".format(tableName) 
      } 
     } 
    } 

    @Test 
    def testRejectsInsertWhenAlreadyInTable() { 
    // "INSERT INTO %s VALUES (...)".format(tableName) 
    } 

    def tableName = "personas" 
} 
+0

哪里是JUnit的快照回购?根据build.xml https://github.com/KentBeck/junit/blob/master/build.xml#L306,我应该在https://oss.sonatype.org/content/repositories/snapshots上找到它,但只有4.9 .1在那里。 –

+0

我认为有一个错误。每晚构建似乎是4.9.1而不是4.11-SNAPSHOT。我通过电子邮件发送了维护人员。 –

+0

4.9.1-SNAPSHOT不包含ChainRule,因此它可能是4.9.1而不是4.11。非常感谢你的帮助! –

0

如何:

abstract class DatabaseTest { 

    // "TRUNCATE %s".format(tableName) 

    def tableName 
} 

class PersonasTest extends DatabaseTest { 
    @Before 
    def addPersona() { 
    // "INSERT INTO %s VALUES (...)".format(tableName) 
    } 

    @Test 
    def testRejectsInsertWhenAlreadyInTable() { 
    // "INSERT INTO %s VALUES (...)".format(tableName) 
    } 

    def tableName = "personas" 
} 

毕竟,PersonasTest是,一个DatabaseTest