是否可以在接口内创建JUnit规则

时间:2014-08-03 05:20:17

标签: java interface junit junit-rule

我正在尝试使用JUnit创建测试自动化套件。对于所有测试,我想创建一个规则,为此我创建了一个接口并将规则放在其中。我想要运行的任何测试都必须实现该接口。它没有抛出任何编译器错误,但是,当我的Test类实现该接口时,这似乎不起作用。 以下是我创建的界面。

public interface IBaseTest {
    @Rule
    public TestRule test = new TestWatcher(){
        @Override
        protected void starting(Description description)
        {
            System.out.println("Starting Test: " + description);
        }
    };
}

或者,我可以创建上面的类并从该类扩展我的所有测试类,我尝试了它并且它工作得很好,但是这会阻止我从任何其他类扩展我的测试方法。

有没有办法让我创建适用于我所有测试的规则而不从基类扩展?

1 个答案:

答案 0 :(得分:1)

是的,有一种我知道的方式,但它会让你写一些额外的代码。

首先,JUnit忽略TestRule的原因是因为它在接口上声明为静态(和最终)。

要解决这个问题,我们需要编写一个这样的自定义跑步者:

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import org.junit.Rule;
import org.junit.rules.TestRule;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;

public final class MyRunner extends BlockJUnit4ClassRunner {

    public MyRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    protected List<TestRule> getTestRules(Object target) {
        List<TestRule> testRules = super.getTestRules(target);
        testRules.addAll(getStaticFieldTestRules(target));
        return testRules;
    }

    private List<TestRule> getStaticFieldTestRules(Object target) {
        List<TestRule> testRules = new ArrayList<>();
        Class<?> clazz = target.getClass();
        for (Field f : clazz.getFields()) {
            if ((f.getModifiers() & Modifier.STATIC) != 0) {
                if (f.isAnnotationPresent(Rule.class)) {
                    try {
                        testRules.add((TestRule) f.get(target));
                    } catch (IllegalArgumentException | IllegalAccessException e) {
                        throw new IllegalStateException(e);
                    }
                }
            }
        }
        return testRules;
    }
}

最后,注释您的测试类以使用新的自定义运行器运行,并且一切都如您所愿......

import org.junit.runner.RunWith;

@RunWith(MyRunner.class)
public class Test implements IBaseTest {

    @org.junit.Test
    public void testName1() throws Exception {
    }

    @org.junit.Test
    public void testName2() throws Exception {

    }

}