Dienstag, 13. Oktober 2009

JUnitExt Prerequisite as JUnit 4.7 Rule

The JUnit 4 Extensions project provides a annotation for specify precondition for a test. For example you have a database integration test, it makes no sense to run this test when the database is down. Therefor you can use the JUnit 4 Extension annotation @Prerequisite. But the disadvantage is, you must use a JUnit 4 Extension specific JUnit test runner @RunWith(AnnotationRunner.class). The Problem with the runner is when you must use a other runner for example the spring DI test runner in the test the approach did not work well.

But a feature like the @Prerequisite annotation of JUnit 4 Extensions project is very nice to have. In JUnit 4.7 there for the JUnit rules comes in mind, here is a small code example how a rule solution for the @Prerequisite annotation can look like.


Here the test with the @Prerequisite annotation and without specific test runner:


public class DatabaseTest {

@Rule
public PrerequisiteRule rule = new PrerequisiteRule();

@Test
@Prerequisite(requires="databaseIsAvailable")
public void testFindAllUsers() throws Exception {
// Database test stuff here
}

@Test
public void testGetDataSource() throws Exception {
// No Database test stuff here
}

public boolean databaseIsAvailable(){
return false;
}

}


The test result will be:



























This test without errors can look like this one:



public class DatabaseTest {

@Rule
public PrerequisiteRule rule = new PrerequisiteRule();

@Test
@Prerequisite(requires="databaseIsAvailable")
public void testFindAllUsers() throws Exception {
// Database test stuff here
}

@Test
public void testGetDataSource() throws Exception {
// No Database test stuff here
}

public boolean databaseIsAvailable(){
return true;
}


}



And here a very basic rule implementation for the test:


public class PrerequisiteRule implements MethodRule{

public Statement apply(final Statement base, final FrameworkMethod method, final Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
Prerequisite annotation = method.getMethod().getAnnotation(Prerequisite.class);
if(annotation != null){
String requiresMethodname = annotation.requires();
Method requiresMethod = target.getClass().getMethod(requiresMethodname);
Boolean result = (Boolean) requiresMethod.invoke(target);
if(!result.equals(true)){
fail("Test requires "+requiresMethodname);
}
}
base.evaluate();
}
};
}

}


Ok the implementation of the rule is very basic there is no good error handling for example ...

Feel free for comments ...

Links:
- http://junitext.sourceforge.net/
- http://www.junit.org/