Skip to content

Tips and Tricks

Andreas Schmid edited this page Apr 25, 2015 · 15 revisions

DataProvider for Spring Integration Testing

To use the junit-dataprovider together with Spring integration testing, i.e. tests which have to run with the SpringJUnit4ClassRunner, you need to create a new JUnit runner similar to

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

public class DataProviderRunnerWithSpring extends SpringJUnit4ClassRunner {
    /* ... */
}

The body of this class is identical with DataProviderRunner.java but needs a small hack to work. Without any modification a NullPointerException is thrown in

  void invokeBeforeClass() {
    Statement statement = new Statement() {
      @Override
      public void evaluate() {
        // nothing to do here
      }
    };
    statement = super.withBeforeClasses(statement);
    try {
      statement.evaluate();
    } catch (Throwable e) {
      failure = e;
    }
  }

The simplest solution is to comment out statement.evaluate();, which obviously breaks the @BeforeClass annotation. Alternatively, replacing the function above by the following two functions also fixes the issue without breaking @BeforeClass.

  void invokeBeforeClass() {
    Statement statement = new Statement() {
      @Override
      public void evaluate() {
        // nothing to do here
      }
    };
    Statement runBeforeTestClassCallbacks = super.withBeforeClasses(statement);

    // ATTENTION: This hack breaks "org.springframework.test.context.support.AbstractTestExecutionListener.beforeTestClass(TestContext)" 
    // as it will never be called
    Statement next = getNextFromRunBeforeTestClassCallbacks(runBeforeTestClassCallbacks);
    try {
      next.evaluate();
    } catch (Throwable e) {
      failure = e;
    }
  }

  private Statement getNextFromRunBeforeTestClassCallbacks(Statement junitBeforeClasses) {
    try {
      Field nextField = junitBeforeClasses.getClass().getDeclaredField("next");
      nextField.setAccessible(true);
      return ((Statement) nextField.get(junitBeforeClasses));
    } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
      throw new RuntimeException("Could not get 'next'-Field from 'runBeforeTestClassCallbacks' statement.", e);
    }
  }

This workaround results in org.springframework.test.context.support.AbstractTestExecutionListener.beforeTestClass(TestContext) to never be called. As the default implementation of this method does not contain any operations, this should be acceptable in most cases.