2011-11-02 77 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