10

我正在使用 junit 4 的“参数化”功能,我注意到 @parameters 方法在 @beforeclass 方法之前执行。这给我带来了一个问题,因为我通过@parameters 传递给测试用例的参数取决于@beforeclass 方法中的代码初始化。例如

@RunWith(Parameterized.class)
public class TestOtherClass {

    String argument;
    private static boolean initializeThis;

    public TestOtherClass(String parameter) throws Exception {
        argument=parameter;
    }

    @BeforeClass
    public static void doSetup() {
        System.out.println("Doing setup before class...");
        initializeThis=true; // true or false, based on some condition
    }

    @Test
    public void otherTest() {
        System.out.println("Other test: " + argument);
    }

    @Parameters
    public static Collection<Object[]> getData(){
        System.out.println("Inside parameter");
        String addThis;
        if(initializeThis)
            addThis="adding true";
        else
            addThis="adding false";

        Object[] para1 = new Object[]{"First parameter :: " + addThis};
        Object[] para2 = new Object[]{"Second parameter :: " + addThis};

        Collection<Object[]> classNames = new ArrayList<Object[]>();
        classNames.add(para1);
        classNames.add(para2);
        return classNames;
    }
}

现在,我在@beforeclass 方法中将变量“initializeThis”初始化为true,但是(令人惊讶的是)当我执行它打印的测试用例时

Other test: First parameter :: adding false
Other test: Second parameter :: adding false

这是意料之外的事情。
我的问题是;有没有办法在@parameters 之前执行@beforeclass 方法,我们可以在junit 4 中执行此操作吗?

4

4 回答 4

6

我会使用普通的旧 java static {..} 初始化程序而不是 @BeforeClass,例如:

@RunWith(Parameterized.class)
public class TestOtherClass {

    String argument;
    private static boolean initializeThis;

    public TestOtherClass(String parameter) throws Exception {
        argument=parameter;
    }

    static {
        doSetup();
    }

    // @BeforeClass
    public static void doSetup() {
        System.out.println("Doing setup before class...");
        initializeThis=true; // true or false, based on some condition
    }

    @Test
    public void otherTest() {
        System.out.println("Other test: " + argument);
    }

    @Parameters
    public static Collection<Object[]> getData(){
        System.out.println("Inside parameter");
        String addThis;
        if(initializeThis)
            addThis="adding true";
        else
            addThis="adding false";

        Object[] para1 = new Object[]{"First parameter :: " + addThis};
        Object[] para2 = new Object[]{"Second parameter :: " + addThis};

        Collection<Object[]> classNames = new ArrayList<Object[]>();
        classNames.add(para1);
        classNames.add(para2);
        return classNames;
    }
}

我知道的唯一缺点是从这里继承的类将无法覆盖静态初始化程序,而 @BeforeClass 在这方面提供了一些自由;

于 2013-02-20T14:40:54.407 回答
4

这是一个老问题,但我最近遇到了同样的问题。令我震惊的是,似乎没有一个解决方案适用于最明显的解决方法——在 @Parameters 方法中调用 @BeforeClass 方法。后者是静态的并且只执行一次——在任何测试运行之前。因此,从所有意图和目的来看,它都是 @BeforeClass 方法,即使它没有被这样注释。更多细节可以在这里找到:http: //feraldeveloper.blogspot.co.uk/2013/12/beforeclass-and-parametrized-junit-tests.html

于 2013-12-28T22:15:17.167 回答
1

RunnerJUnit为参数列表中的每一项创建一个,一个Runner是封装测试方法的东西。所以@Parameters总是会在@BeforeClass 之前执行。

但是,您可以将 @Parameterized 与Assume结合使用。无论您是否打算执行它,您总是在列表中包含所有参数。然后在测试方法中,针对该值添加assumeTrue()which 测试。initializeThis

@RunWith(Parameterized.class)
public class TestOtherClassAssume {
  private final String argument;
  private final boolean initializeThisTest;
  private static boolean initializeThis;

  @Parameters
  public static Collection<Object[]> getData(){
    System.out.println("Inside parameter");

    return Arrays.asList(new Object[][] {
      { false, "First" },
      { true, "Second" },
    });
  }

  public TestOtherClassAssume(boolean initializeThisTest, String argument) {
    this.initializeThisTest = initializeThisTest;
    this.argument = argument;
  }

  @BeforeClass
  public static void doSetup() {
    System.out.println("Doing setup before class...");
    initializeThis = true; // true or false, based on some condition
  }

  @Test
  public void otherTest() {
    Assume.assumeTrue(initializeThis == initializeThisTest);
    System.out.println("Other test: " + argument);
  }
}

输出是:

Inside parameter
Doing setup before class...
Other test: Second
于 2012-07-11T13:46:47.327 回答
0

但是,这不适用于 TestSuites。给定

@RunWith(Parameterized.class)
public class TogglableParameterizedTest {
    static boolean useAllParameters = false;

    int parameter;

    public TogglableParameterizedTest(int parameter) {
        super();
        this.parameter = parameter;
    }
    @Parameters
    public static Collection<Object[]> getTestParameters() {
        List<Object[]> parameters = new ArrayList<Object[]>();
        if(useAllParameters) {
            parameters.add(new Object[] { 1 });
            parameters.add(new Object[] { 2 });
            parameters.add(new Object[] { 3 });
        }
        else {
            parameters.add(new Object[] { 1 });
        }
        return parameters;
    }
    @Test
    public void test() {
        System.out.println("parameter=" + parameter);
    }
}

这不起作用:

@RunWith(Suite.class)
@SuiteClasses({ TogglableParameterizedTest.class })
public class NonWorkingTestSuite1 {

    @BeforeClass
    public static void toggle() {
        System.out.println("sets flag to late!");
    }

}

输出是

sets flag to late!
parameter=1

也不是:

@RunWith(Suite.class)
@SuiteClasses({ TogglableParameterizedTest.class }) 
public class NonWorkingTestSuite2 {
    static {
        System.out.println("sets flag still to late");
        TogglableParameterizedTest.useAllParameters = true;
    }
}

输出为“参数=1”。所以静态初始化程序根本没有执行。我找到了以下解决方法。扩展“Suite”并在那里插入静态初始化器:

public class TogglingSuite extends Suite {

    static {
        System.out.println("sets flag early enough!");
        TogglableParameterizedTest.useAllParameters = true;
    }

    public TogglingSuite(Class<?> klass, Class<?>[] suiteClasses)
        throws InitializationError {
        super(klass, suiteClasses);
    }

    public TogglingSuite(Class<?> klass, List<Runner> runners)
        throws InitializationError {
        super(klass, runners);
    }

    public TogglingSuite(Class<?> klass, RunnerBuilder builder)
            throws InitializationError {
        super(klass, builder);
    }

    public TogglingSuite(RunnerBuilder builder, Class<?> klass,
            Class<?>[] suiteClasses) throws InitializationError {
        super(builder, klass, suiteClasses);
    }

    public TogglingSuite(RunnerBuilder builder, Class<?>[] classes)
            throws InitializationError {
        super(builder, classes);
    }
}

并在您的测试套件中使用它:

@RunWith(TogglingSuite.class)
@SuiteClasses({ TogglableParameterizedTest.class })
public class WorkingTestSuite {

}

输出是

sets flag early enough!
parameter=1
parameter=2
parameter=3

现在它起作用了。

于 2013-05-03T01:07:10.910 回答