how to combine @RunWith with @RunWith(Parameterized.class)
Asked Answered
S

1

10

I implemented a runner class A.class inherited from BlockJUnit4ClassRunner so that I can annotate tests with @RunWith(A.class). At the same time, sb. else annotate the tests with RunWith(Parameterized.class). It is obvious we cannot use two @RunWith at the same time.

How to solve this problem? or how to merge these two @RunWith?

Sedulous answered 2/1, 2015 at 17:1 Comment(0)
A
13

I believe this does what you want:

package so.junit.runner;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.model.InitializationError;
import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters;
import org.junit.runners.parameterized.ParametersRunnerFactory;
import org.junit.runners.parameterized.TestWithParameters;

import java.util.Arrays;

@RunWith(Parameterized.class)
@Parameterized.UseParametersRunnerFactory(CustomParameterizedTest.RunnerFactory.class)
public class CustomParameterizedTest {

  @Parameterized.Parameters
  public static Iterable<Integer> data() {
    return Arrays.asList(new Integer[]{1, 2, 3});
  }

  private int i;

  public CustomParameterizedTest(int i) {
    this.i = i;
  }

  @Test
  public void test() {
    System.out.println(i);
  }

  public static class RunnerFactory implements ParametersRunnerFactory {
    @Override
    public org.junit.runner.Runner createRunnerForTestWithParameters(TestWithParameters test) throws InitializationError {
      return new A(test);
    }
  }

  public static class A extends BlockJUnit4ClassRunnerWithParameters {
    private final Object[] parameters;

    public A(TestWithParameters test) throws InitializationError {
      super(test);
      parameters = test.getParameters().toArray(new Object[test.getParameters().size()]);
    }

    @Override
    public Object createTest() throws Exception {
      return getTestClass().getOnlyConstructor().newInstance(parameters);
    }
  }
}

Based on the Javadocs in the JUnit Parameterized class, this is how they expect you to create a custom test runner that supports parameterization.

UPDATE

Updated to name the custom runner A

Anele answered 3/1, 2015 at 1:40 Comment(12)
Thanks for your answer. But in your code I could not figure out where is my A.class?Sedulous
public static class Runner extends BlockJUnit4ClassRunnerWithParameters is the same as your A.class, it can be your custom runner implementation (and supports parameterization)Anele
I corrected the example. The class Runner has to extend you A runner. @Anele Hopefully this is ok for you. I didn't want to create a new Answer.Ky
@Stefan, this modified version will not work because the custom runner must extend BlockJUnit4ClassRunnerWithParameters to support parameterization. I believe my original example was exactly what the original question asked for, i just named the custom runner Runner instead of AAnele
It doesn't have to extend BlockJUnit4ClassRunnerWithParameters. This feature is designed for reusing existing runners without modifying them. Hence you can simply extend your current runner A by an mechanism that injects the parameters.Ky
Thanks Alex and Stefan. I have trouble to run the code because my system cannot import org.junit.runners.parameterized (shows cannot find the symbol). But I believe the code should be correct. So I accept the answer.Sedulous
@user389955, according to the JUnit Javadocs at junit.org/javadoc/latest/org/junit/runners/Parameterized.html, this class was available starting at 4.0, what version of JUnit are you using?Anele
@Alex: junit = 4. it does not complain import org.junit.runners.Parameterized; it complained: import org.junit.runners.parameterized.XXXSedulous
@user389955, Ah, it looks like they added ParametersRunnerFactory in 4.12, so it seems this customizable Parameterized stuff is pretty new. Hopefully you are able to update your JUnit to the latest version thenAnele
This doesn't appear to be working with @MockitoJUnitRunner. The constructor then has to take a parameter Class<?> klass, so I have no idea how to set the parameters. I'm interested in Stefan Birkner's comment about "simply extending the current runner". Could you possibly explain about this?Answer
MockitoJUnitRunner also doesn't appear to have the methods createTest or getTestClass. I'll trying looking at the source code but if anyone's cracked this it'd be great to hear from you!Answer
@mike You're right that it's much more difficult for Mockito's runner, because it doesn't directly inherit from BlockJUnit4ClassRunner, but instead is a wrapper around a Runner surrogate in an internal package. In general this would probably require modifying the original runner or rewrapping a deliberately-opaque org.mockito.internal.runners implementation, but for this particular case the point is moot because the MockitoJUnitRunner is all but deprecated in favor of an equivalent Rule anyway.Cathe

© 2022 - 2024 — McMap. All rights reserved.