javajunit5junit5-extension-model

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 È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.


Solution

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