我有一个特性,在块之前添加了几个测试。具体实例的@Before块在特征中的那些块之前运行。糟糕,这意味着我无法截断数据库表,然后插入fixture:
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块进行排序的正确方法是什么?我总是可以在特征中声明truncate
,然后在子类中有一个@Before方法,但是我必须记住让我的所有子类都调用截断方法。
在Scala 2.9.0.1上使用JUnit 4.10。
答案 0 :(得分:4)
执行此操作的正确方法是使用@Rule
,扩展@ExternalResource
以用于类型行为之前和之后(在Java语法中):
@Rule
public ExternalResource resource= new ExternalResource() {
@Override
protected void before() throws Throwable {
myServer.connect();
};
@Override
protected void after() {
myServer.disconnect();
};
};
您可以使用@Rule
(在4.10中引入)按顺序将多个@RuleChain
连接在一起,并再次使用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应用于方法和字段。
这已经修复(由我),并已合并为主,但不幸的是,它尚未发布:它将成为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"
}
答案 1 :(得分: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
是-a DatabaseTest
。