Novice User
Novice User

Reputation: 3824

Register Extensions automatically in JUnit

I am extending JUnit's ParameterResolver to provide a custom argument in Test methods.

 public class MyParameterResolver implements ParameterResolver {

    @Override
    public boolean supportsParameter(ParameterContext parameterContext,
            ExtensionContext extensionContext) throws ParameterResolutionException {
        return parameterContext.getParameter().getType() == MyWrapper.class;
    }

    @Override
    public Object resolveParameter(ParameterContext parameterContext,
            ExtensionContext extensionContext) throws ParameterResolutionException {

        // Do something about getting MyAnnotation

        return new MyWrapper();
    }

}

and then using it in test methods using ExtendWith

@ExtendWith(MyParameterResolver.class)
@Test
@MyAnnotation(val = 20)
@MyAnnotation(val = 30)    
void test(MyWrapper wrapper) {
    System.out.println(wrapper);
}

It works perfectly however I do not like the idea that all the tests which needs this extension would need to be annotated with @ExtendWith(MyParameterResolver.class) , is it possible to automatically register the annotation in Junit programmatically whenever a test method contains MyWrapper parameter or MyAnnotation annotation?

Upvotes: 4

Views: 3787

Answers (1)

Slaw
Slaw

Reputation: 46116

§5.2 of the JUnit 5 User Guide shows the three ways one can register extensions:

  1. Declaratively with @ExtendWith (§5.2.1).

    Developers can register one or more extensions declaratively by annotating a test interface, test class, test method, or custom composed annotation with @ExtendWith(…​) and supplying class references for the extensions to register.

    Note: If you annotate the class with @ExtendWith(...) then all enclosed test methods will be extended by the specified extension.

  2. Programmatically with @RegisterExtension (§5.2.2).

    Developers can register extensions programmatically by annotating fields in test classes with @RegisterExtension.

    When an extension is registered declaratively via @ExtendWith, it can typically only be configured via annotations. In contrast, when an extension is registered via @RegisterExtension, it can be configured programmatically — for example, in order to pass arguments to the extension’s constructor, a static factory method, or a builder API.

  3. Automatically via java.util.ServiceLoader (§5.2.3).

    In addition to declarative extension registration and programmatic extension registration support using annotations, JUnit Jupiter also supports global extension registration via Java’s java.util.ServiceLoader mechanism, allowing third-party extensions to be auto-detected and automatically registered based on what is available in the classpath.

    Specifically, a custom extension can be registered by supplying its fully qualified class name in a file named org.junit.jupiter.api.extension.Extension within the /META-INF/services folder in its enclosing JAR file.

    Note: Automatic registration must be explicitly enabled.

If you're okay with your extension being registered globally then you can use the automatic registration mechanism. But there does not appear to be a way to only extend test methods if they have a specific parameter type. However, you may be able to create a so-called composed annotation to make things simpler:

@ExtendWith(MyParameterResolver.class)
@Retention(RUNTIME)
@Target(METHOD)
public @interface ComposedAnnotation {

  int[] vals(); // int array to (maybe?) replace the multiple @MyAnnotation(val = XXX) annotations
}

Though I don't know if that's compatible with your @MyAnnotation annotation.

Note that if your implementation of #supportsParameter(ParameterContext,ExtensionContext) is quick then having the extension registered for methods which don't use it should not be a problem. In other words, it won't significantly slow down your tests or, as far as I know, cause errors.

Upvotes: 4

Related Questions