Running JUnit tests with and without before / after interception

I have a situation where I need to be able to run a JUnit test suite in two different modes:

  • In the first mode are used @Before

    and @After

    annotations / techniques; but...
  • In the second mode, don't use these annotations / methods, but run the same methods @Test

For example:

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.
    }
}

      

In "mode # 1" I need methods @Before

and @After

( start()

and stop()

accordingly) to execute before / after testWidget()

. But in "mode # 2" I would only like the method to testWidget()

work.

The best I can think of is this:

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.
    }
}

      

But then this presents an additional problem: how do I paste useHooks

into my test suite? This is hacky too, and I think, I hope, JUnit supports this use case out of the box.

Is there a way to do this? If so, how?

+3


source to share


3 answers


Check @Category

annotation



+1


source


I suggest considering this solution:

  • Write a custom JUnit runner
  • Add a VM parameter to switch between the two required modes

Here is the custom runner code I came up with:



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);
    }

}

      

All you have to do is start the JUnits VM with the added option: -Drun-befores-and-afters

and annotate your test class with @RunWith(MyJUnitRunner.class)

and then you are done.

+1


source


What you are looking for is Parameterized Tests , so the code would look like this (not tested)

@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;
    }
    ....
}

      

+1


source







All Articles