问题描述
限时送ChatGPT账号..我定义了自己的 JUnit 注释:
@ParameterizedTest@MethodSource("myorg.qartesting.DataProviders#standardDataProvider")@Tags({@Tag("ccr"), @Tag("standard")})公共@interface CcrStandardTest {}
然后,我可以在测试中使用该注释:
@CcrStandardTestpublic void E0010_contact_standard (String testData) {...
我的运行配置:
JVM 选项:-ea
类:myorg.qartestingrstandardtests.CcrStanConTest
- 这是 IDE 建议的(经过验证指向正确的类,该类包含我的原型测试方法)
然而,这会导致:jupiter.api.extension.ParameterResolutionException:没有为方法 [public void...
我尝试从测试方法签名中删除 String testData
但随后 JUnit 没有执行任何测试:No tests found
当我在原型测试方法上方添加 @Test
时,它会执行:
@CcrStandardTest
下定义的注释似乎都没有应用IDE 建议 @Test 和参数化源的可疑组合
(我已经知道
@ParameterizedTest
意味着 @Test
,只是不知道为什么 IDE 能够找到自定义注释而 JUnit 不能?) 解决方案 如您所见,您需要添加 @Retention(RUNTIME)
到您的组合注释,以便 JUnit看见.Java 中的注释具有三种不同的保留策略:
RetentionPolicy.SOURCE
注释将被编译器丢弃.
RetentionPolicy.CLASS
注释将由编译器记录在类文件中,但在运行时不需要由 VM 保留.这是默认行为. [强调]
RetentionPolicy.RUNTIME
注解会被编译器记录在类文件中,并在运行时由虚拟机保留,因此可以反射读取.
正如我上面强调的,如果您没有明确添加 @Retention(...)
,则使用 CLASS
策略.这不适用于 JUnit,因为 JUnit 不会扫描 *.class
文件(即字节码)以获取注释,它会反射性地扫描 加载的 类以查找测试方法.如果没有 RUNTIME
保留策略,您的注释将无法反射访问,因此 JUnit 永远不会看到它,因此不会执行测试.
@Target
注释:
指示注释类型适用的上下文.注释类型可能适用的声明上下文和类型上下文在 JLS 9.6.4.1 中指定,并在源代码中由 java.lang.annotation.ElementType
.>
如果 @Target
元注解不存在于注解类型 T
上,那么 T
类型的注解可以写成除类型参数声明外的任何声明的修饰符.
如果存在 @Target
元注释,编译器将强制执行 ElementType
枚举常量指示的使用限制,符合 JLS 9.7.4.
在我对你的其他问题的回答中,我使用了:
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
因为这与 @ParameterizedTest
.我认为将其限制为 METHOD
是个好主意,因为 @ParameterizedTest
的设计者显然认为只有方法应该由参数化测试扩展直接扩展(参见 §5 扩展模型).并且包含 ANNOTATION_TYPE
允许您将组合注释放在另一个注释上,从而创建另一个组合注释.
您还会看到我包含了 @Documented
:
如果注解 @Documented
出现在注解类型 A
的声明中,则任何 @A
> 元素上的注释被视为元素公共契约的一部分.更详细地说,当注解类型 A
用 Documented
进行注解时,A 类型的注解的存在和值
是 A
注释元素的公共契约的一部分.相反,如果注释类型 B
没有用 Documented
注释,则 B
的存在和值 注释不是 B
注释元素的公共契约的一部分.具体来说,如果一个注解类型用 Documented
进行注解,默认情况下,像 javadoc 这样的工具将在其输出中显示该类型的注解,而没有 Documented
的注解类型的注解不会被显示.
请注意,这些注释(@Retention
、@Target
和 @Documented
)并非特定于 JUnit.这些注释是 Java 中注释如何工作的基础,每个注释都驻留在 java.lang.annotation
包中.
I defined my own JUnit annotation:
@ParameterizedTest
@MethodSource("myorg.qartesting.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.qartestingrstandardtests.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:
@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?)
解决方案
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.
这篇关于JUnit5-Jupiter:组合(=“元")注释无法解析为注释定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论