问题
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 testData
from the test method signature but then JUnit is not executing any tests:No tests found
When I add
@Test
above my prototype test method, it executes but:- It seems like none of the annotations I defined under
@CcrStandardTest
are applied - IDE suggests
suspicious combination @Test and parameterized source
(I already know@ParameterizedTest
implies@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
@Target
meta-annotation is not present on an annotation typeT
, then an annotation of typeT
may be written as a modifier for any declaration except a type parameter declaration.If an
@Target
meta-annotation is present, the compiler will enforce the usage restrictions indicated byElementType
enum 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
@Documented
is present on the declaration of an annotation typeA
, then any@A
annotation on an element is considered part of the element's public contract. In more detail, when an annotation typeA
is annotated withDocumented
, the presence and value of annotations of typeA
are a part of the public contract of the elementsA
annotates. Conversely, if an annotation typeB
is not annotated withDocumented
, the presence and value ofB
annotations are not part of the public contract of the elementsB
annotates. 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 withoutDocumented
will 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