How to define a JUnit method rule in a test suite?

前端 未结 5 1861
孤街浪徒
孤街浪徒 2020-11-30 08:03

I have a class that is a JUnit suite of JUnit test classes. I would like to define a rule on the suite to do something to the database before and a

相关标签:
5条回答
  • 2020-11-30 08:26

    By itself, adding a rule to the class annotated with @RunWith(Suite.class) won't do the trick. I believe this is because a Suite is a ParentRunner<Runner> rather than a Runner such as BlockJUnit4ClassRunner which would attempt to scrape rules on the classes it runs. To run its children, it tells the child Runners to run. Those Runners may have built up their tests by applying rules on those classes, but the Suite runner doesn't take any special action to apply rules from itself to the tests its child Runners build.

    0 讨论(0)
  • 2020-11-30 08:31

    Have you tried to use "test class hierarchy" ? I often use abstract test class to share test or fixture. For example, all my DB test are initialising an embedded datasource. I first create an abstract "DbTestCase" class which handles the init logic. Then all subclass will benefit the test and the fixtures.

    However, sometimes I encounter problem when my test cases requires many test/fixture-logic that I can't store in a single hierarchy. In this case, only aspect programming solves the issue. Marking test/fixture-logic through specific annotation/interfaces that any required-class can implement.

    You can optionnaly consider handling the "aspect" using a custom runner that will "inject" test/fixture-logic depending on annotation/interface of tested classes.

    0 讨论(0)
  • 2020-11-30 08:43

    You can use a RunListener that you add to the Suite. It doesn't give you everything a Rule can do, but it will provide you a Description class which should have the annotations available. At least, I don't think JUnit filters it down to its understood annotations only.

    The developer of JUnit just discussed the mechanics of adding a RunListener to a Suite here.

    0 讨论(0)
  • 2020-11-30 08:45

    This can be done, but it needs a bit of work. You need to define your own Suite runner and your own Test runner as well, and then override runChild() in the test runner. Using the following:

    AllTests.java:

    @RunWith(MySuite.class)
    @SuiteClasses({Class1Test.class})
    public class AllTests {
    }
    

    Class1Test.java:

    public class Class1Test {
        @Deprecated @Test public void test1() {
            System.out.println("" + this.getClass().getName() + " test1");
        }
    
        @Test public void test2() {
            System.out.println("" + this.getClass().getName() + " test2");
        }
    }
    

    Note that I've annotated test1() with @Deprecated. You want to do something different when you have the @Deprecated annotation on the test, so we need to extend Suite to use a custom Runner:

    public class MySuite extends Suite {
        // copied from Suite
        private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError {
            Suite.SuiteClasses annotation = klass.getAnnotation(Suite.SuiteClasses.class);
            if (annotation == null) {
                throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", klass.getName()));
            }
            return annotation.value();
        }
    
        // copied from Suite
        public MySuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
            super(null, getRunners(getAnnotatedClasses(klass)));
        }
    
        public static List<Runner> getRunners(Class<?>[] classes) throws InitializationError {
            List<Runner> runners = new LinkedList<Runner>();
    
            for (Class<?> klazz : classes) {
                runners.add(new MyRunner(klazz));
            }
    
            return runners;
        }
    }
    

    JUnit creates a Runner for each test it will run. Normally, Suite would just create the default BlockJUnit4ClassRunner, all we're doing here is overriding the constructor for the Suite which reads the classes from the SuiteClass annotation and we're creating our own runners with them, MyRunner. This is our MyRunner class:

    public class MyRunner extends BlockJUnit4ClassRunner {
        public MyRunner(Class<?> klass) throws InitializationError {
            super(klass);
        }
    
        @Override
        protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
            Description description= describeChild(method);
            if (method.getAnnotation(Ignore.class) != null) {
                notifier.fireTestIgnored(description);
            } else {
                if (description.getAnnotation(Deprecated.class) != null) {
                    System.out.println("name=" + description.getMethodName() + " annotations=" + description.getAnnotations());
                }
                runLeaf(methodBlock(method), description, notifier);
            }
        }
    }
    

    Most of this is copied from BlockJUnit4ClassRunner. The bit I've added is:

    if (description.getAnnotation(Deprecated.class) != null) {
        System.out.println("name=" + description.getMethodName() + " annotations=" + description.getAnnotations());
    }
    

    where we test for the existence of the @Deprecated annotation on the method, and do something if it's there. The rest is left as an exercise for the reader. When I run the above Suite, I get as output:

    name=test1 annotations=[@java.lang.Deprecated(), @org.junit.Test(expected=class org.junit.Test$None, timeout=0)]
    uk.co.farwell.junit.run.Class1Test test1
    uk.co.farwell.junit.run.Class1Test test2
    

    Please note that Suite has multiple constructors depending upon how it is invoked. The above works with Eclipse, but I haven't tested other ways of running the Suite. See the comments alongside the various constructors for Suite for more information.

    0 讨论(0)
  • 2020-11-30 08:48

    You can group tests with TestNG. And you can configure TestNG to run some logic @BeforeGroup and @AfterGroup.

    0 讨论(0)
提交回复
热议问题