Really useful for when you need to repeat test setup/teardown in multiple test classes.
Imagine have a server and before we run the tests we want to call server.start() and after the tests are finished we want to call server.stop().
We create a rule that implements junit's 'TestRule' class which starts and stops the server:
Now, our test class doesn't need the two methods annotated with beforeclass and afterclass, only the rule:
Note the use of @ClassRule. An alternate annotation would be @Rule which would mean that the server was stopped and started between every test.
Now imagine that we want to clear down server state between each test. Logically, this belongs in the rule we have already created. We want one rule to manage server state entirely, such that the rule starts and stops the server beforeclass and afterclass but clears the state between each test.
However, in the recent version of Junit, the rule variable in our test needs to be static.
The way round it is the following. Firstly, we modify our rule to behave so that if the server has been started it clears the state when the apply method is called:
Then in our junit test we must use both rule annotations for a @ClassRule and @Rule.
Imagine have a server and before we run the tests we want to call server.start() and after the tests are finished we want to call server.stop().
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static final Scassandra SERVER | |
= ScassandraFactory.createServer(binaryPort, | |
adminPort); | |
@BeforeClass | |
public static void startScassandra() { | |
SERVER.start(); | |
} | |
@AfterClass | |
public void stopCassandra() { | |
SERVER.stop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class ScassandraServerRule implements TestRule { | |
private Scassandra scassandra; | |
public ScassandraServerRule(Scassandra scassandra){ | |
this.scassandra = scassandra; | |
} | |
@Override | |
public Statement apply(final Statement base, | |
Description description) { | |
return new Statement() { | |
@Override | |
public void evaluate() throws Throwable { | |
scassandra.start(); | |
try { | |
base.evaluate(); | |
} | |
finally { | |
scassandra.stop(); | |
} | |
} | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static final Scassandra SERVER | |
= ScassandraFactory.createServer(binaryPort, | |
adminPort); | |
@ClassRule | |
public static ScassandraServerRule rule | |
= new ScassandraServerRule(SERVER); |
Note the use of @ClassRule. An alternate annotation would be @Rule which would mean that the server was stopped and started between every test.
Combining Before and BeforeClass behaviour in one rule
Now imagine that we want to clear down server state between each test. Logically, this belongs in the rule we have already created. We want one rule to manage server state entirely, such that the rule starts and stops the server beforeclass and afterclass but clears the state between each test.
However, in the recent version of Junit, the rule variable in our test needs to be static.
The way round it is the following. Firstly, we modify our rule to behave so that if the server has been started it clears the state when the apply method is called:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public Statement apply(final Statement base, Description description) { | |
return new Statement() { | |
@Override | |
public void evaluate() throws Throwable { | |
if (!started) { | |
started = true; | |
scassandra.start(); | |
try { | |
base.evaluate(); | |
} finally { | |
scassandra.stop(); | |
} | |
} else { | |
scassandra.clearState(); | |
base.evaluate(); | |
} | |
} | |
}; | |
} |
Then in our junit test we must use both rule annotations for a @ClassRule and @Rule.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static final Scassandra SERVER | |
= ScassandraFactory.createServer(binaryPort, | |
adminPort); | |
@ClassRule | |
public static ScassandraServerRule classRule | |
= new ScassandraServerRule(SERVER); | |
@Rule | |
public ScassandraServerRule rule | |
= classRule; |
Thanks for sharing :-)
ReplyDelete