Bevor Bevor - 3 months ago 13
Java Question

JUnit: @Rule's overridden apply method not executed under test

I created a JUnit rule to rollback a javax.persistence transaction when any exception occurs (otherwise all further tests will fail since the transaction is in an inconsistent condition). The problem is that my rule will never be executed when the test starts, strictly speaking: the

apply
method is never executed. it does not even work when I put the @Rule declaration into the concrete class and initialize the transactionRule within the test. Here is how it looks like:

THE RULE

public class TransactionRule implements TestRule
{
private EntityManager entityManager;

public TransactionRule(EntityManager entityManager)
{
this.entityManager = entityManager;
}

@Override
public Statement apply(Statement base, Description description)
{
return new TransactionStatement(base);
}

public class TransactionStatement extends Statement
{
private final Statement runningTest;

public TransactionStatement(Statement runningTest)
{
this.runningTest = runningTest;
}

@Override
public void evaluate() throws Throwable
{
try
{
runningTest.evaluate();
}
catch (Exception e)
{
if (entityManager.getTransaction().isActive())
{
entityManager.getTransaction().rollback();
}
}
}
}
}


THE ABSTRACT CLASS THAT USES THE RULE

public abstract class AbstractIntegrationTest
{
//more members vars

@Rule
public TransactionRule transactionRule;

@BeforeClass
public static void setUpBeforeClass()
{
loadProperties();
entityManagerFactory = Persistence.createEntityManagerFactory("MyCuisinePersistenceTestUnit", connectionProperties);
entityManager = entityManagerFactory.createEntityManager();
}

@Before
public void setUp()
{
transactionRule = new TransactionRule(entityManager);

entityManager.clear();
}

//more code
}


THE TEST CLASS WITH THE DEFECTIVE TEST

public class RecipePersistenceITest extends AbstractIntegrationTest
{
//more tests

@Test
public void persistenceOfRecipeWithUserCategorySuccessful()
{
//Test that fails
}
}


Any ideas?

Answer

Test rules are invoked before methods annotated with @Before, so trying to assign a rule in @Before will have no effect (although I would have expected it to throw an exception instead).

Instead assign the rule on definition (and make the field final), and do any additional config (if necessary) in your @Before.

Note that each test method is executed in a new instance of the test class, so defining a rule as a final field is no problem.