Skip to content

WrappingParameterizedRunner

xkr47 edited this page Oct 31, 2014 · 12 revisions

NOTE: This documentation assumes you know the basics of the Parameterized runner.

Purpose

The main purpose of this JUnit runner is to support the scenario where you want to combine the functionality of @RunWith(Parameterized.class) with @RunWith(SomethingElse) - a scenario neither supported by JUnit nor by the Parameterized runner. WrappingParameterizedRunner overcomes this through a chaining annotation which lets one specify a second runner to run the parameterized tests with.

The WrappingParameterizedRunner runner also works as a direct replacement for the Parameterized runner in cases when no other runner is needed, providing an alternative syntax (compared to Parameterized) to specify tests.

Usage

The runner is activated by annotating the test class with @RunWith(WrappingParameterizedRunner.class).

The runner requires the test class to contain a method which is called to determine which parameter sets the tests are to be run with. Just like with the standard Parameterized builder, the parameters are then passed to the constructor of the test class when the tests are to be run.

The test class can have multiple constructors; the parameter types are used to determine which constructor to use in each case. This resolution is done immediately when the parameters are given to the runner; thus failure to give correct parameters are detected while the parameters are generated and it's easy to find how the broken parameters came to be. This resolution is done even when only a single constructor exists to get the same benefits.

The method for creating parameter sets must be declared in the test class as such:

    @ParameterizedSuite
    public static void suite(ParameterizedSuiteBuilder builder) {
        ...
    }

The name of the method does not matter. Inside the method the provided builder instance is used to register the parameters for constructing the test class. Example:

       builder.constructWith("hello", 42);

This call will thus throw an exception if it cannot find a constructor in the test class that accepts the given arguments. Example acceptable constructor:

    public MyTestClass(String input, int itemNo) {
        this.input = input;
        this.itemNo = itemNo;
    }

If you want to parameterize the MockitoJUnitRunner runner, you add the following annotation to the test class:

@WrappedRunWith(MockitoJUnitRunner.class)

When the annotation is not present, the default JUnit4 runner is used.

Compatibility

WrappingParameterizedRunner is expected to be compatible with:

  • all runners that
    • don't apply any custom classloading of the test class
    • instantiate the test class using the default constructor
  • powermock (1.5.5 and newer) which does indeed apply custom classloading (explicit support included)

This means:

  • WrappingParameterizedRunner can be used with @WrappedRunWith:
    • default runner (normally used when no @RunWith or @WrappedRunWith annotation present)
    • spring (SpringJUnit4ClassRunner)
    • mockito runner
    • powermock runner
  • can not:
    • Suite runner
    • Enclosed runner (you can use NestedRunner instead - also provided in this project)
    • Categories runner

Note however that WrappingParameterizedRunner can be used inside a class run with the Enclosed runner, or run by another class run with the Suite runner. The above limitations refer to whether they can be used with the @WrappedRunWith annotation or not.

If you find a runner WrappingParameterizedRunner does not work with, file a bug!

Examples

Example that wraps the MockitoJUnitRunner and sets up 3 sets of parameters, one of which has a custom name (shown in the JUnit test tree in Eclipse for example). The default name contains the parameter set index and the parameter values.

@RunWith(WrappingParameterizedRunner.class)
@WrappedRunWith(MockitoJUnitRunner.class)
public class ExampleTest {
	private final String str;
	private final int id;

	@Mock
	private Runnable mock;

	@ParameterizedSuite
	public static void suite(ParameterizedSuiteBuilder builder) {
		builder.constructWith("kala", 1);
		builder.constructWith("foo", 42);
		builder.constructWith("foo", 43).named("test with secret parameters");
	}

	public WrappingParameterizedRunnerTest(String str, int id) {
		this.str = str;
		this.id = id;
	}

	@Test
	public void ensureStringNotNull() throws Exception {
		assertNotNull(str);
	}

	@Test
	public void ensureMockAvailable() throws Exception {
		assertNotNull(mock);
	}

	@Test
	@Ignore
	public void ensureIdAtleast15() throws Exception {
		assertTrue("Id should be at least 15, but was " + id, id >= 15);
	}
}

Another example, this time not wrapping any other runner. Demonstrates that multiple constructors can be used. Tests all combinations of the numbers 0..49 and the strings "foo" and "bar", and additionally with just string "kala".

@RunWith(WrappingParameterizedRunner.class)
public class ExampleTest {
	private final int i;
	private final String x;

	@ParameterizedSuite
	public static void suite(ParameterizedSuiteBuilder builder) {
		for (int i=0; i<50; ++i) {
			for(String x : new String[] { "foo", "bar" }) {
				builder.constructWith(i, x);
			}
		}
		builder.constructWith("kala");
	}

	public WrappingParameterizedRunnerTest(int i, String x) {
		this.i = i;
		this.x = x;
	}

	public WrappingParameterizedRunnerTest(String x) {
		this.i = 42;
		this.x = x;
	}


	@Test
	public void testSomeNonsense() throws Exception {
		asserEquals("123", x + i);
	}
}
Clone this wiki locally