Home > Software engineering >  How do I convert this test rule to JUnit5?
How do I convert this test rule to JUnit5?

Time:05-10

I have some custom rule using junit4 which I would like to convert to junit5. However I'm not able to find good documentation on migrating a MethodRule implementation other than that I should be using junit5 extension instead of rule.

public class MyRule implements MethodRule {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyRule.class);

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyAnnotation { }

    @Override
    public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) {
        Statement result = statement;
        if (hasMyAnnotation(frameworkMethod)) {
                result = new Statement() {
                    @Override
                    public void evaluate() {
                        LOGGER.info("Skipping test");
                    }
                };
            }
        }
        return result;
    }

    private static boolean hasMyAnnotation(final Annotatable frameworkMethod) {
        return frameworkMethod.getAnnotation(MyAnnotation.class) != null;
    }

My class is using junit4 Statement, FrameworkMethod etc to find out if my method has an annotation... then to skip it. How can I convert this?

CodePudding user response:

Solution 1, Disable test with custom annotation
JUnit 5 provides a type of extension that can control whether or not a test should be run. This is defined by implementing the ExecutionCondition interface.
Extension implementation:

import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.AnnotationUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;

public class SkipConditionExtension implements ExecutionCondition {
    private static final Logger LOGGER = LoggerFactory.getLogger(SkipConditionExtension.class);

    @Override
    public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
        AnnotatedElement element = context.getElement().orElse(null);

        if (hasMyAnnotation(element, MyAnnotation.class)) {
            LOGGER.info(() ->"Skipping test");
            return ConditionEvaluationResult.disabled(String.format("Skipped test: %s by @MyAnnotation", element));
        }

        return ConditionEvaluationResult.enabled("Test enabled");
    }

    private <T extends Annotation>  boolean hasMyAnnotation(final AnnotatedElement element, Class<T> annotation) {
        return element != null && AnnotationUtils.findAnnotation(element, annotation).isPresent();
    }
}

Registring extenssion:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(SkipConditionExtension.class)
public class TestObject {
    @Test
    public void test1() {

    }

    @Test
    @MyAnnotation
    public void test2() {

    }
}

Output:

INFO: Skipping test
Skipped test: public void com.test.TestObject.test2() by @MyAnnotation

Solution 2, Skip test via invocation interseptor
InvocationInterceptor iterface defines the API for Extensions that wish to intercept calls to test.
Current implementation will behave exactly like your previous Rule.
Extension implementation:

import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.InvocationInterceptor;
import org.junit.jupiter.api.extension.ReflectiveInvocationContext;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.AnnotationUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;

public class SkipCondition implements InvocationInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(SkipConditionExtension.class);

    @Override
    public void interceptTestMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) throws Throwable {
        AnnotatedElement element = extensionContext.getElement().orElse(null);
        if (hasMyAnnotation(element, MyAnnotation.class)) {
            LOGGER.info(() ->"Skipping test");
            invocation.skip();
        } else {
            invocation.proceed();
        }
    }

    private <T extends Annotation>  boolean hasMyAnnotation(final AnnotatedElement element, Class<T> annotation) {
        return element != null && AnnotationUtils.findAnnotation(element, annotation).isPresent();
    }
}

Registring extenssion:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

@ExtendWith(SkipCondition.class)
public class TestObject {
    @Test
    public void test1() {

    }

    @Test
    @MyAnnotation
    public void test2() {

    }
}

Please note, you can perform automatic extension registration according to documentation.

  • Related