Java 使用前后挂钩运行JUnit测试

Java 使用前后挂钩运行JUnit测试,java,junit,Java,Junit,我需要能够在两种不同的“模式”下运行一套JUnit测试: 在第一种模式下,在使用注释/方法之前使用@和之后使用@;但是 在第二种模式下,不要使用这些注释/方法,而是运行相同的@Test方法 例如: public class WidgetTest { @Before void start() { // Do some start up work. } @After void stop() { // Do some shu

我需要能够在两种不同的“模式”下运行一套JUnit测试:

  • 在第一种模式下,在使用注释/方法之前使用
    @
    和之后使用
    @;但是
  • 在第二种模式下,不要使用这些注释/方法,而是运行相同的
    @Test
    方法
例如:

public class WidgetTest {
    @Before
    void start() {
        // Do some start up work.
    }

    @After
    void stop() {
        // Do some shutdown work.
    }

    @Test
    public void testWidget() {
        // Given/When/Then, etc.
    }
}
在“模式1”中,我希望在
testWidget()之前/之后执行
方法(
start()
stop()
)。但是在“模式2”中,我只希望启动
testWidget()
方法

我能想到的最好办法是:

public class WidgetTest {
    private boolean useHooks;

    // Ctor, getter and setter for 'useHooks'.

    @Before
    void start() {
        if(useHooks) {
            // Do some start up work.
        }
    }

    @After
    void stop() {
        if(useHooks) {
            // Do some shutdown work.
        }
    }

    @Test
    public void testWidget() {
        // Given/When/Then, etc.
    }
}
但这又带来了一个额外的问题:如何将
useHooks
注入到测试套件中?它也是一种黑客行为,我想我希望JUnit支持这种开箱即用的用例


有没有办法做到这一点?如果是这样,如何?

< P>检查<代码> @类别< /代码>注释< /P> < P>我建议考虑这个解决方案:

  • 编写自定义JUnit runner
  • 添加VM参数以在两种所需模式之间切换
以下是我找到的自定义跑步者的代码:

import java.util.Collections;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.internal.runners.statements.RunAfters;
import org.junit.internal.runners.statements.RunBefores;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;

public class MyJUnitRunner extends BlockJUnit4ClassRunner {

    private final boolean runBeforesAndAfters = System.getProperty("run-befores-and-afters") != null;

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

    @Override
    protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) {
        List<FrameworkMethod> befores = Collections.EMPTY_LIST;
        if (runBeforesAndAfters) {
            befores = getTestClass().getAnnotatedMethods(Before.class);
        }
        return befores.isEmpty() ? statement : new RunBefores(statement, befores, target);
    }

    @Override
    protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
        List<FrameworkMethod> afters = Collections.EMPTY_LIST;
        if (runBeforesAndAfters) {
            afters = getTestClass().getAnnotatedMethods(After.class);
        }
        return afters.isEmpty() ? statement : new RunAfters(statement, afters, target);
    }

}
import java.util.Collections;
导入java.util.List;
导入org.junit.After;
导入org.junit.Before;
导入org.junit.internal.runners.statements.runafter;
导入org.junit.internal.runners.statements.RunBefores;
导入org.junit.runners.BlockJUnit4ClassRunner;
导入org.junit.runners.model.FrameworkMethod;
导入org.junit.runners.model.InitializationError;
导入org.junit.runners.model.Statement;
公共类MyJUnitRunner扩展了BlockJUnit4ClassRunner{
私有最终布尔值runbeforesandafter=System.getProperty(“runbefores and after”)!=null;
公共MyJUnitRunner(类klass)引发初始化错误{
超级(klass);;
}
@凌驾
带befores的受保护语句(FrameworkMethod方法、对象目标、语句){
List befores=Collections.EMPTY_List;
if(运行前和运行后){
befores=getTestClass().getAnnotatedMethods(Before.class);
}
return befores.isEmpty()?语句:new RunBefores(语句,befores,目标);
}
@凌驾
带after的受保护语句(FrameworkMethod方法、对象目标、语句){
List after=Collections.EMPTY_List;
if(运行前和运行后){
After=getTestClass().getAnnotatedMethods(After.class);
}
return after.isEmpty()?语句:新建runafter(语句、after、目标);
}
}

你所要做的就是启动JUnits虚拟机,并添加以下选项:
-Drun before and after
,用
@RunWith(MyJUnitRunner.class)
注释你的测试类,然后你就完成了。

你想要的是,所以你的代码看起来像这样(未测试)

@RunWith(参数化的.class)
公共类Widgetest{
@参数
公共静态收集数据(){
返回Arrays.asList(新对象[]{true,false});
}
私有布尔钩子
公共Widgetest(booelan useHooks){
this.useHooks=useHooks;
}
....
}
谢谢@robocoder(+1)-这是一个不错的建议,但这意味着我需要在两个地方定义我的
testWidget()
方法(一个在使用这些启动/停止方法的测试类中,另一个在不使用它们的测试类中)。对我来说,这是太多的重复代码了,因为每个测试类都有几十个测试方法,而我有数百个测试类。思想?再次感谢!
@RunWith(Parameterized.class)
public class WidgetTest {
    @Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[] {true, false});
    }

    private boolean useHooks

    public WidgetTest(booelan useHooks) {
        this.useHooks = useHooks;
    }
    ....
}