JUnit5-Jupiter:组合 (="meta") 注释未解析为注释定义
JUnit5-Jupiter: Composed (="meta") annotation does not resolve to annotation definition
我定义了自己的 JUnit 注解:
@ParameterizedTest
@MethodSource("myorg.qa.ccrtesting.DataProviders#standardDataProvider")
@Tags({@Tag("ccr"), @Tag("standard")})
public @interface CcrStandardTest {
}
然后,我能够在我的测试中使用该注释:
@CcrStandardTest
public void E0010_contact_standard (String testData) {
...
- 我的运行配置:
JVM 选项:-ea
Class:myorg.qa.ccrtesting.ccrstandardtests.CcrStanConTest
- 这是由 IDE 建议的(并且已验证指向正确的 class,其中包含我的原型测试方法)
但是,这会导致:jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [java.lang.String arg0] in method [public void...
我尝试从测试方法签名中删除 String testData
但是 JUnit 没有执行任何测试:No tests found
当我在原型测试方法上方添加 @Test
时,它执行但是:
- 似乎应用了我在
@CcrStandardTest
下定义的注释中的 none 个
- IDE 建议
suspicious combination @Test and parameterized source
(我已经知道 @ParameterizedTest
意味着 @Test
,只是不确定为什么 IDE 能够找到自定义注释而 JUnit 却不能?)
经过一些调查,我发现通过添加:@Retention(RUNIME)
(需要两次导入),元注释定义将被解析。
JUnit 文档实际上在他们的组合注释示例中展示了这一点 (@Retention
)。
他们还显示 @Target
也与它一起使用。
- 但都不解释...
这个答案不是最高质量的,因为我不知道 @Retention
和 @Target
做了什么,但我希望它能帮助和我遇到同样问题的人得到去。
如果有人详细说明,我将很乐意编辑此答案或接受他们的答案!
如您所见,您需要将 @Retention(RUNTIME)
添加到组合注释中,以便 JUnit 能够看到它。 Java 中的注释具有三种不同的保留策略:
-
Annotations are to be discarded by the compiler.
-
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]
-
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.
正如我在上面强调的那样,如果您没有明确添加 @Retention(...)
,则会使用 CLASS
策略。这不适用于 JUnit,因为 JUnit 不会扫描 *.class
文件(即字节码)以获取注释,它会反射地扫描 loaded 类寻找测试方法。如果没有 RUNTIME
保留策略,您的注释将无法反射访问,因此 JUnit 永远不会看到它,因此不会执行测试。
@Target
注解:
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 type T
, then an annotation of type T
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 by ElementType
enum constants, in line with JLS 9.7.4.
在我对 的回答中,我使用了:
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
因为这与 @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) 使用的目标相同。包括 ANNOTATION_TYPE
允许您将组合注释放置在另一个注释上,从而创建另一个组合注释。
你还会看到我包括了 @Documented
:
If the annotation @Documented
is present on the declaration of an annotation type A
, then any @A
annotation on an element is considered part of the element's public contract. In more detail, when an annotation type A
is annotated with Documented
, the presence and value of annotations of type A
are a part of the public contract of the elements A
annotates. Conversely, if an annotation type B
is not annotated with Documented
, the presence and value of B
annotations are not part of the public contract of the elements B
annotates. Concretely, if an annotation type is annotated with Documented
, by default a tool like javadoc will display annotations of that type in its output while annotations of annotation types without Documented
will not be displayed.
请注意,这些注释——@Retention
、@Target
和 @Documented
——并非特定于 JUnit。这些注释是 Java 中注释工作方式的基础,每个注释都位于 java.lang.annotation
包中。
我定义了自己的 JUnit 注解:
@ParameterizedTest
@MethodSource("myorg.qa.ccrtesting.DataProviders#standardDataProvider")
@Tags({@Tag("ccr"), @Tag("standard")})
public @interface CcrStandardTest {
}
然后,我能够在我的测试中使用该注释:
@CcrStandardTest
public void E0010_contact_standard (String testData) {
...
- 我的运行配置:
JVM 选项:-ea
Class:myorg.qa.ccrtesting.ccrstandardtests.CcrStanConTest
- 这是由 IDE 建议的(并且已验证指向正确的 class,其中包含我的原型测试方法)
但是,这会导致:jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [java.lang.String arg0] in method [public void...
我尝试从测试方法签名中删除
String testData
但是 JUnit 没有执行任何测试:No tests found
当我在原型测试方法上方添加
@Test
时,它执行但是:- 似乎应用了我在
@CcrStandardTest
下定义的注释中的 none 个 - IDE 建议
suspicious combination @Test and parameterized source
(我已经知道@ParameterizedTest
意味着@Test
,只是不确定为什么 IDE 能够找到自定义注释而 JUnit 却不能?)
- 似乎应用了我在
经过一些调查,我发现通过添加:@Retention(RUNIME)
(需要两次导入),元注释定义将被解析。
JUnit 文档实际上在他们的组合注释示例中展示了这一点 (@Retention
)。
他们还显示 @Target
也与它一起使用。
- 但都不解释...
这个答案不是最高质量的,因为我不知道 @Retention
和 @Target
做了什么,但我希望它能帮助和我遇到同样问题的人得到去。
如果有人详细说明,我将很乐意编辑此答案或接受他们的答案!
如您所见,您需要将 @Retention(RUNTIME)
添加到组合注释中,以便 JUnit 能够看到它。 Java 中的注释具有三种不同的保留策略:
-
Annotations are to be discarded by the compiler.
-
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]
-
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.
正如我在上面强调的那样,如果您没有明确添加 @Retention(...)
,则会使用 CLASS
策略。这不适用于 JUnit,因为 JUnit 不会扫描 *.class
文件(即字节码)以获取注释,它会反射地扫描 loaded 类寻找测试方法。如果没有 RUNTIME
保留策略,您的注释将无法反射访问,因此 JUnit 永远不会看到它,因此不会执行测试。
@Target
注解:
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.
在我对
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
因为这与 @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) 使用的目标相同。包括 ANNOTATION_TYPE
允许您将组合注释放置在另一个注释上,从而创建另一个组合注释。
你还会看到我包括了 @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.
请注意,这些注释——@Retention
、@Target
和 @Documented
——并非特定于 JUnit。这些注释是 Java 中注释工作方式的基础,每个注释都位于 java.lang.annotation
包中。