如何将此测试规则转换为 JUnit5?

How do I convert this test rule to JUnit5?

我有一些使用 junit4 的自定义规则,我想将其转换为 junit5。但是我找不到关于迁移 MethodRule 实现的好文档,除了我应该使用 junit5 扩展而不是规则。

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

我的 class 正在使用 junit4 StatementFrameworkMethod 等来查明我的方法是否有注释...然后跳过它。我该如何转换?

解决方案 1,使用自定义注释禁用测试
JUnit 5 提供了一种扩展,可以控制测试是否应该 运行。这是通过实现 ExecutionCondition 接口来定义的。
扩展实现:

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

注册字符串扩展:

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() {

    }
}

输出:

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

方案二,通过调用拦截器跳过测试
InvocationInterceptor 接口为希望拦截测试调用的扩展定义了 API。
当前实施的行为 与您以前的 Rule 完全一样。
扩展实现:

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

注册字符串扩展:

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() {

    }
}

请注意,您可以根据documentation进行自动分机注册。