How to run some code before each JUnit @Test metho

2019-05-06 23:32发布

问题:

use case is simple: I want to run some boiler plate code before each method in JUnit test annotated with @Test and my custom annotation (let's call it @Mine).

I do not want to use following methods (explanation in parenthesis):

  1. @RunWith (my test may, or may not use this annotation already, so I cannot assume that I will be able to use my own runner)
  2. AOP (I cannot make any dependencies to third party libraries, such as AspectJ)

I guess this leaves me with reflection only, which is fine by me. I thought off using @Before accompanied with getting current method via Thread.getCurrentThread() etc. but somehow I find this solution to be a little bit dirty, since I would have to make boiler plate code again within this method to fire reflection (and avoiding any unnecessary code was the goal in the first place).

Maybe you have some other ideas?

回答1:

You need a solution very similar to the answer to Mark unit test as an expected failure, based upon a TestRule. Using the example of a @Deprecated annotation (you can use yours here), you can insert code if the annotation exists on the method. The Description class contains the list of annotations on the method.

public class ExecutionTest {
    public class BeforeExecution implements TestRule {
        public Statement apply(Statement base, Description description) {
            return statement(base, description);
        }

        private Statement statement(final Statement base, final Description description) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    if (description.getAnnotation(Deprecated.class) != null) {
                        // you can do whatever you like here.
                        System.err.println("this will be run when the method has an @Deprecated annotation");
                    }
                    base.evaluate();
                }
            };
        }
    }

    @Rule public BeforeExecution beforeExecution = new BeforeExecution();

    // Will have code executed.
    @Deprecated
    @Test public void test1() {
         // stuff
    }

    // won't have code executed.
    @Test public void test2() {
         // stuff
    }
}


回答2:

I would split the class into two. One with the methods you would have annotated with @mine and one for the others.

Then use @before as normal.

This adds no none standard code and will be easy to understand and maintain for future developers as well.