I have a trait that adds a couple of tests and before blocks. The @Before blocks of the concrete instance are run before the ones in the trait. Oops, this means I can't truncate database tables then insert fixtures:
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 will always succeed because the execution order will be:
addPersonatruncatetestRejectsInsertWhenAlreadyInTableWhat would be the proper way of ordering the @Before blocks without imposing too many constraints on the subclasses? I could always declare truncate in the trait, then have an @Before method in the subclass, but then I have to remember to make all my subclasses call that truncate method.
Using JUnit 4.10 on Scala 2.9.0.1.
The correct way of doing this is to use @Rule, extend @ExternalResource for before and after type behaviour (in Java syntax):
@Rule
public ExternalResource resource= new ExternalResource() {
@Override
protected void before() throws Throwable {
myServer.connect();
};
@Override
protected void after() {
myServer.disconnect();
};
};
You can chain and order multiple @Rules together in order by using the @RuleChain (introduced in 4.10), again in java syntax:
@Rule
public TestRule chain= RuleChain
.outerRule(new LoggingRule("outer rule")
.around(new LoggingRule("middle rule")
.around(new LoggingRule("inner rule");
There is a caveat. You can't specify a public field in scala (public field's are wrapped with accessor methods, and the fields themselves become private). JUnit checks that the @Rule applies to a public field. The fix to change the JUnit code so that you can apply @Rule to methods as well as fields.
This has been fixed (by me), and has been merged into master, but unfortunately, it's not yet released: it will be part of 4.11. So you have two options: use the 4.11-SNAPSHOT, or download the 4.10 release and apply the patch for @Rule.
The scala code could look something like:
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"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With