是否有一种方法可以在JUnit 5测试的ExecutionCondition中访问自定义注解的值?

huangapple go评论70阅读模式
英文:

Is there a way to access values of a custom annotation in a ExecutionCondition of junit 5 tests?

问题

I have the following annotation to mark test code that should not be executed if a server does not listen on a host and port each specified in a properties file:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(DisableOnServerNotListening.class)
public @interface DisabledOnServerNotListening
{
    String propertyNameHost() default "host";
    String propertyNamePort() default "port";
}

In a junit 5 ExecutionCondition, I want to look up the actual configured host/port values from the property file to decide if the test should be run (port is listening) or not (port is not listening). Because there may be more than one host/port configuration in my tests, I need to be flexible regarding property names. So how can I access the values of the annotation? Debugging shows that there is a field called testDescriptor in ExtensionContext, but it is not exposed for access.

英文:

I have the following annotation to mark test code that should not be executed if a server does not listen on a host and port each specified in a properties file:

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(DisableOnServerNotListening.class)
public @interface DisabledOnServerNotListening
{
	String propertyNameHost() default "host";
	String propertyNamePort() default "port";
}

In a junit 5 ÈxecutionCondition I want to look up the actual configured host/port values from the property file to decide if the test should be run (port is listening) or not
(port is not listening). Because there may be more than one host/port configuration in my tests I need to be flexible regarding property names. So how can I access the values of the annotation? Debugging shows that there is a field called testDescriptor in ExtensionContext, but it is not exposed for access.

答案1

得分: 1

Looking at existing Jupiter functionality you can see that most existing implementations of ExecutionCondition work with annotations. Thus, what you want to do is possible.

Let's look at (parts of) the implementation of DisabledCondition:


import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation;


class DisabledCondition implements ExecutionCondition {

    private static final ConditionEvaluationResult ENABLED = ConditionEvaluationResult.enabled(
        "@Disabled is not present");

    @Override
    public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
        AnnotatedElement element = context.getElement().orElse(null);
        return findAnnotation(element, Disabled.class) //
                .map(annotation -> toResult(element, annotation)) //
                .orElse(ENABLED);
    }

    private ConditionEvaluationResult toResult(AnnotatedElement element, Disabled annotation) {
        String value = annotation.value();
        String reason = StringUtils.isNotBlank(value) ? value : element + " is @Disabled";
        return ConditionEvaluationResult.disabled(reason);
    }

}

If you replace Disabled with DisabledOnServerNotListening you have a head start on the implementation of your own ExecutionCondition subtype.

The actual checking code for host availability would probably reside within the toResult method. Similar to:

private ConditionEvaluationResult toResult(AnnotatedElement element, DisabledOnServerNotListening annotation) {
    String hostPropName = annotation.propertyNameHost();
    String portPropName = annotation.propertyNamePort();
    boolean disabled = !checkIfHostIsListening(hostPropName, portPropName);
    if (disabled) 
        return ConditionEvaluationResult.disabled("host not listening");
    else
        return ConditionEvaluationResult.enabled();
}
英文:

Looking at existing Jupiter functionality you can see that most existing implementations of ExecutionCondition work with annotations. Thus, what you want to do is possible.

Let's look at (parts of) the implementation of DisabledCondition:


import static org.junit.platform.commons.util.AnnotationUtils.findAnnotation;


class DisabledCondition implements ExecutionCondition {

	private static final ConditionEvaluationResult ENABLED = ConditionEvaluationResult.enabled(
		"@Disabled is not present");

	@Override
	public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
		AnnotatedElement element = context.getElement().orElse(null);
		return findAnnotation(element, Disabled.class) //
				.map(annotation -> toResult(element, annotation)) //
				.orElse(ENABLED);
	}

	private ConditionEvaluationResult toResult(AnnotatedElement element, Disabled annotation) {
		String value = annotation.value();
		String reason = StringUtils.isNotBlank(value) ? value : element + " is @Disabled";
		return ConditionEvaluationResult.disabled(reason);
	}

}

If you replace Disabled with DisabledOnServerNotListening you have a head start on the implementation of your own ExecutionCondition subtype.

The actual checking code for host availability would probably reside within the toResult method. Similar to:

private ConditionEvaluationResult toResult(AnnotatedElement element, DisabledOnServerNotListening annotation) {
    String hostPropName = annotation.propertyNameHost();
    String portPropName = annotation.propertyNamePort();
    boolean disabled = !checkIfHostIsListening(hostPropName, portPropName);
    if (disabled) 
        return ConditionEvaluationResult.disabled("host not listening");
    else
        return ConditionEvaluationResult.enabled();
}

huangapple
  • 本文由 发表于 2023年7月4日 21:48:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76613310.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定