问题
I defined my own JUnit annotation:
@ParameterizedTest
@MethodSource("myorg.qa.ccrtesting.DataProviders#standardDataProvider")
@Tags({@Tag("ccr"), @Tag("standard")})
public @interface CcrStandardTest {
}
Then, I was able to use that annotation in my tests:
@CcrStandardTest
public void E0010_contact_standard (String testData) {
...
- My run configuration:
JVM options:-ea
Class:myorg.qa.ccrtesting.ccrstandardtests.CcrStanConTest- This was suggested by the IDE (and is verified to point to the correct class, which holds my prototype test method)
However, this results in: jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [java.lang.String arg0] in method [public void...
I tried removing
String testDatafrom the test method signature but then JUnit is not executing any tests:No tests foundWhen I add
@Testabove my prototype test method, it executes but:- It seems like none of the annotations I defined under
@CcrStandardTestare applied - IDE suggests
suspicious combination @Test and parameterized source
(I already know@ParameterizedTestimplies@Test, just not sure why IDE is able to find the custom annotation but JUnit isn't?)
- It seems like none of the annotations I defined under
回答1:
As you've discovered, you need to add @Retention(RUNTIME) to your composed annotation in order for JUnit to see it. Annotations in Java have three different retention policies:
RetentionPolicy.SOURCE
Annotations are to be discarded by the compiler.
RetentionPolicy.CLASS
Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time. This is the default behavior. [emphasis added]
RetentionPolicy.RUNTIME
Annotations are to be recorded in the class file by the compiler and retained by the VM at run time, so they may be read reflectively.
As I emphasized above, if you don't explicitly add @Retention(...) then the CLASS policy is used. This won't work with JUnit because JUnit doesn't scan the *.class files (i.e. byte-code) for the annotations, it scans the loaded classes reflectively to find test methods. Without a RUNTIME retention policy your annotation is not reflectively accessible, thus JUnit never sees it and consequently doesn't execute the test.
The @Target annotation:
Indicates the contexts in which an annotation type is applicable. The declaration contexts and type contexts in which an annotation type may be applicable are specified in JLS 9.6.4.1, and denoted in source code by enum constants of java.lang.annotation.ElementType.
If an
@Targetmeta-annotation is not present on an annotation typeT, then an annotation of typeTmay be written as a modifier for any declaration except a type parameter declaration.If an
@Targetmeta-annotation is present, the compiler will enforce the usage restrictions indicated byElementTypeenum constants, in line with JLS 9.7.4.
In my answer to your other question I used:
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
Because that's the same targets used by @ParameterizedTest. I figured it was a good idea to restrict it to METHOD since the designers of @ParameterizedTest apparently feel that only methods should be directly extended by the parameterized-tests extension (see §5 Extension Model). And including ANNOTATION_TYPE allows you to place your composed annotation on another annotation, creating yet another composed annotation.
You'll also see I included @Documented:
If the annotation
@Documentedis present on the declaration of an annotation typeA, then any@Aannotation on an element is considered part of the element's public contract. In more detail, when an annotation typeAis annotated withDocumented, the presence and value of annotations of typeAare a part of the public contract of the elementsAannotates. Conversely, if an annotation typeBis not annotated withDocumented, the presence and value ofBannotations are not part of the public contract of the elementsBannotates. Concretely, if an annotation type is annotated withDocumented, by default a tool like javadoc will display annotations of that type in its output while annotations of annotation types withoutDocumentedwill not be displayed.
Notice that theses annotations—@Retention, @Target, and @Documented—are not specific to JUnit. These annotations are fundamental to how annotations in Java work and each one resides in the java.lang.annotation package.
回答2:
Upon some investigation, I found that by adding: @Retention(RUNIME) (two imports will be required), meta annotation definition will be resolved.
JUnit docs actually show this (@Retention) in their example of composed annotations.
They also show @Target being used with it as well.
- But explain neither...
This answer isn't the highest quality, as I don't know what @Retention and @Target do but I hope it'll help anyone stuck with the same problem as me to get going.
If someone elaborates, I will be happy to edit this answer or accept theirs!
来源:https://stackoverflow.com/questions/60339277/junit5-jupiter-composed-meta-annotation-does-not-resolve-to-annotation-def