如何获取 JUnit 测试套件的注释 class?
How to get annotations of JUnit test suite class?
我有这样一个测试套件示例 class 到 运行 许多测试 class 在 JUnit 4.13 中一次。
@RunWith(Suite.class)
@SuiteClasses({
FirstTest.class,
SecondTest.class
})
@TestSuiteAnnotation
public class TestSuite {
}
这些是我的测试 classes.
@FirstAnnotation
public class FirstTest extends ExtTest {
@Test
public void test() {
}
}
@SecondAnnotation
public class SecondTest extends ExtTest {
@Test
public void test() {
}
}
public class ExtTest {
@Before
public void beforeMethod() {
System.out.println("Annotations from " + this.getClass());
Arrays.asList(this.getClass().getAnnotations()).forEach(System.out::println);
}
}
当我从TestSuite.class运行测试时,控制台输出是:
Annotations from class FirstTest
@FirstAnnotation()
Annotations from class SecondTest
@SecondAnnotation()
目前,this.getClass().getAnnotations()
returns 来自测试 class 的注释(即 FirstTest.class、SecondTest.class)。当我从 TestSuite.class.
运行 测试时,我想获得注释 @TestSuiteAnnotation
预期的输出应该是:
Annotations from class FirstTest
@FirstAnnotation()
@TestSuiteAnnotation()
Annotations from class SecondTest
@SecondAnnotation()
@TestSuiteAnnotation()
当我从 TestSuite.class 进行 运行 测试时,我能否以某种方式获得注释 @TestSuiteAnnotation
?
您有多种选择:
JUnit 4 运行 监听器
在 JUnit 4 上,您可以注册一个 RunListener
,如 @nrainer 所说。如果您使用 Maven 构建,很容易注册一个 运行 侦听器,如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<includes>
<include>org.acme.TestSuite</include>
</includes>
<properties>
<property>
<name>listener</name>
<value>org.acme.SuiteRunListener</value>
</property>
</properties>
</configuration>
</plugin>
运行 侦听器可以覆盖事件 testSuiteStarted
和 testSuiteFinished
并直接记录您感兴趣的注释或将它们分配给静态线程局部变量,如 [= testSuiteStarted
中的 19=],然后在 testSuiteFinished
中再次取消分配。
这在 Maven 中运行良好,我对其进行了测试。不幸的是,没有直接支持 运行ning 测试与来自 IDEs 的 运行 监听器,如 IntelliJ IDEA 或 Eclipse。因此,如果您想避免 运行 使用 here 所示的主要方法从 class 手动执行测试,因为它会带走所有不错的 IDE 测试报告从套件向下钻取到测试 class 到测试方法,这不是一个选项。
JUnit 5 测试执行侦听器
类似于 JUnit 4 的 运行 侦听器,您可以注册一个 TestExecutionListener
for your JUnit 5 tests. The advantage in JUnit 5 is that you can register it globally via Java's s ServiceLoader 机制,即它会在引导 JUnit 时被拾取并且也应该在 IDE 中工作。我对另一种类型的扩展做了类似的事情,它在 IntelliJ IDEA 中运行良好,当然在 Maven 中也运行良好。
带有自定义套件的 JUnit 4 运行ner
回到 JUnit 4,我们可以通过声明一种特殊类型的套件来使用 运行 侦听器扩展第一种方法。您只需使用该套件而不是 org.junit.runners.Suite
,就可以在 Maven 和 IDE 中享受工作的 运行 侦听器。它是这样工作的,为方便起见,另请参阅我的MCVE on GitHub:
package org.acme;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.stream.Collectors;
public class SuiteRunListener extends RunListener {
private static ThreadLocal<String> currentSuiteName = new ThreadLocal<String>();
private static ThreadLocal<List<Annotation>> currentSuiteAnnotations = new ThreadLocal<>();
@Override
public void testSuiteStarted(Description description) throws Exception {
super.testSuiteStarted(description);
final RunWith runWith = description.getAnnotation(RunWith.class);
if (runWith != null && runWith.value().equals(SuiteWithListener.class)) {
currentSuiteName.set(description.getDisplayName());
currentSuiteAnnotations.set(
description.getAnnotations().stream()
.filter(annotation -> {
final Class<? extends Annotation> annotationType = annotation.annotationType();
return !(annotationType.equals(RunWith.class) || annotationType.equals(SuiteClasses.class));
})
.collect(Collectors.toList())
);
}
}
@Override
public void testSuiteFinished(Description description) throws Exception {
super.testSuiteFinished(description);
final RunWith runWith = description.getAnnotation(RunWith.class);
if (runWith != null && runWith.value().equals(SuiteWithListener.class)) {
currentSuiteName.set(null);
currentSuiteAnnotations.set(null);
}
}
public static String getCurrentSuiteName() {
return currentSuiteName.get();
}
public static List<Annotation> getCurrentSuiteAnnotations() {
return currentSuiteAnnotations.get();
}
}
package org.acme;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerBuilder;
import java.util.List;
public class SuiteWithListener extends Suite {
public SuiteWithListener(Class<?> klass, RunnerBuilder builder) throws InitializationError {
super(klass, builder);
}
public SuiteWithListener(RunnerBuilder builder, Class<?>[] classes) throws InitializationError {
super(builder, classes);
}
protected SuiteWithListener(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
super(klass, suiteClasses);
}
protected SuiteWithListener(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
super(builder, klass, suiteClasses);
}
protected SuiteWithListener(Class<?> klass, List<Runner> runners) throws InitializationError {
super(klass, runners);
}
@Override
public void run(RunNotifier notifier) {
notifier.addListener(new SuiteRunListener()); // !!!
super.run(notifier);
}
}
package org.acme;
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(SuiteWithListener.class) // !!!
@SuiteClasses({
FirstTest.class,
SecondTest.class
})
@TestSuiteAnnotation
public class TestSuite {}
package org.acme;
import org.junit.Before;
import java.util.Arrays;
public class ExtTest {
@Before
public void beforeMethod() {
String currentSuiteName = SuiteRunListener.getCurrentSuiteName();
if (currentSuiteName != null) {
System.out.println("Annotations from suite " + currentSuiteName);
SuiteRunListener.getCurrentSuiteAnnotations().forEach(System.out::println);
}
System.out.println("Annotations from class " + this.getClass());
Arrays.asList(this.getClass().getAnnotations()).forEach(System.out::println);
System.out.println();
}
}
现在 运行 连接您的套件时,您应该会看到如下输出:
Annotations from suite org.acme.TestSuite
@org.acme.TestSuiteAnnotation()
Annotations from class class org.acme.FirstTest
@org.acme.FirstAnnotation()
Annotations from suite org.acme.TestSuite
@org.acme.TestSuiteAnnotation()
Annotations from class class org.acme.SecondTest
@org.acme.SecondAnnotation()
请注意: 我假设您确实需要从每个测试方法访问当前套件,而不仅仅是在测试 class 或套件级别。如果你不需要它并且让 运行 侦听器在套件启动时做一些事情就足够了 and/or 完成,当然你不需要当前套件名称的 getter 方法和套件注释。我只是扩展了你自己的例子。
我有这样一个测试套件示例 class 到 运行 许多测试 class 在 JUnit 4.13 中一次。
@RunWith(Suite.class)
@SuiteClasses({
FirstTest.class,
SecondTest.class
})
@TestSuiteAnnotation
public class TestSuite {
}
这些是我的测试 classes.
@FirstAnnotation
public class FirstTest extends ExtTest {
@Test
public void test() {
}
}
@SecondAnnotation
public class SecondTest extends ExtTest {
@Test
public void test() {
}
}
public class ExtTest {
@Before
public void beforeMethod() {
System.out.println("Annotations from " + this.getClass());
Arrays.asList(this.getClass().getAnnotations()).forEach(System.out::println);
}
}
当我从TestSuite.class运行测试时,控制台输出是:
Annotations from class FirstTest
@FirstAnnotation()
Annotations from class SecondTest
@SecondAnnotation()
目前,this.getClass().getAnnotations()
returns 来自测试 class 的注释(即 FirstTest.class、SecondTest.class)。当我从 TestSuite.class.
@TestSuiteAnnotation
预期的输出应该是:
Annotations from class FirstTest
@FirstAnnotation()
@TestSuiteAnnotation()
Annotations from class SecondTest
@SecondAnnotation()
@TestSuiteAnnotation()
当我从 TestSuite.class 进行 运行 测试时,我能否以某种方式获得注释 @TestSuiteAnnotation
?
您有多种选择:
JUnit 4 运行 监听器
在 JUnit 4 上,您可以注册一个 RunListener
,如 @nrainer 所说。如果您使用 Maven 构建,很容易注册一个 运行 侦听器,如下所示:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<includes>
<include>org.acme.TestSuite</include>
</includes>
<properties>
<property>
<name>listener</name>
<value>org.acme.SuiteRunListener</value>
</property>
</properties>
</configuration>
</plugin>
运行 侦听器可以覆盖事件 testSuiteStarted
和 testSuiteFinished
并直接记录您感兴趣的注释或将它们分配给静态线程局部变量,如 [= testSuiteStarted
中的 19=],然后在 testSuiteFinished
中再次取消分配。
这在 Maven 中运行良好,我对其进行了测试。不幸的是,没有直接支持 运行ning 测试与来自 IDEs 的 运行 监听器,如 IntelliJ IDEA 或 Eclipse。因此,如果您想避免 运行 使用 here 所示的主要方法从 class 手动执行测试,因为它会带走所有不错的 IDE 测试报告从套件向下钻取到测试 class 到测试方法,这不是一个选项。
JUnit 5 测试执行侦听器
类似于 JUnit 4 的 运行 侦听器,您可以注册一个 TestExecutionListener
for your JUnit 5 tests. The advantage in JUnit 5 is that you can register it globally via Java's s ServiceLoader 机制,即它会在引导 JUnit 时被拾取并且也应该在 IDE 中工作。我对另一种类型的扩展做了类似的事情,它在 IntelliJ IDEA 中运行良好,当然在 Maven 中也运行良好。
带有自定义套件的 JUnit 4 运行ner
回到 JUnit 4,我们可以通过声明一种特殊类型的套件来使用 运行 侦听器扩展第一种方法。您只需使用该套件而不是 org.junit.runners.Suite
,就可以在 Maven 和 IDE 中享受工作的 运行 侦听器。它是这样工作的,为方便起见,另请参阅我的MCVE on GitHub:
package org.acme;
import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.stream.Collectors;
public class SuiteRunListener extends RunListener {
private static ThreadLocal<String> currentSuiteName = new ThreadLocal<String>();
private static ThreadLocal<List<Annotation>> currentSuiteAnnotations = new ThreadLocal<>();
@Override
public void testSuiteStarted(Description description) throws Exception {
super.testSuiteStarted(description);
final RunWith runWith = description.getAnnotation(RunWith.class);
if (runWith != null && runWith.value().equals(SuiteWithListener.class)) {
currentSuiteName.set(description.getDisplayName());
currentSuiteAnnotations.set(
description.getAnnotations().stream()
.filter(annotation -> {
final Class<? extends Annotation> annotationType = annotation.annotationType();
return !(annotationType.equals(RunWith.class) || annotationType.equals(SuiteClasses.class));
})
.collect(Collectors.toList())
);
}
}
@Override
public void testSuiteFinished(Description description) throws Exception {
super.testSuiteFinished(description);
final RunWith runWith = description.getAnnotation(RunWith.class);
if (runWith != null && runWith.value().equals(SuiteWithListener.class)) {
currentSuiteName.set(null);
currentSuiteAnnotations.set(null);
}
}
public static String getCurrentSuiteName() {
return currentSuiteName.get();
}
public static List<Annotation> getCurrentSuiteAnnotations() {
return currentSuiteAnnotations.get();
}
}
package org.acme;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerBuilder;
import java.util.List;
public class SuiteWithListener extends Suite {
public SuiteWithListener(Class<?> klass, RunnerBuilder builder) throws InitializationError {
super(klass, builder);
}
public SuiteWithListener(RunnerBuilder builder, Class<?>[] classes) throws InitializationError {
super(builder, classes);
}
protected SuiteWithListener(Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
super(klass, suiteClasses);
}
protected SuiteWithListener(RunnerBuilder builder, Class<?> klass, Class<?>[] suiteClasses) throws InitializationError {
super(builder, klass, suiteClasses);
}
protected SuiteWithListener(Class<?> klass, List<Runner> runners) throws InitializationError {
super(klass, runners);
}
@Override
public void run(RunNotifier notifier) {
notifier.addListener(new SuiteRunListener()); // !!!
super.run(notifier);
}
}
package org.acme;
import org.junit.runner.RunWith;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(SuiteWithListener.class) // !!!
@SuiteClasses({
FirstTest.class,
SecondTest.class
})
@TestSuiteAnnotation
public class TestSuite {}
package org.acme;
import org.junit.Before;
import java.util.Arrays;
public class ExtTest {
@Before
public void beforeMethod() {
String currentSuiteName = SuiteRunListener.getCurrentSuiteName();
if (currentSuiteName != null) {
System.out.println("Annotations from suite " + currentSuiteName);
SuiteRunListener.getCurrentSuiteAnnotations().forEach(System.out::println);
}
System.out.println("Annotations from class " + this.getClass());
Arrays.asList(this.getClass().getAnnotations()).forEach(System.out::println);
System.out.println();
}
}
现在 运行 连接您的套件时,您应该会看到如下输出:
Annotations from suite org.acme.TestSuite
@org.acme.TestSuiteAnnotation()
Annotations from class class org.acme.FirstTest
@org.acme.FirstAnnotation()
Annotations from suite org.acme.TestSuite
@org.acme.TestSuiteAnnotation()
Annotations from class class org.acme.SecondTest
@org.acme.SecondAnnotation()
请注意: 我假设您确实需要从每个测试方法访问当前套件,而不仅仅是在测试 class 或套件级别。如果你不需要它并且让 运行 侦听器在套件启动时做一些事情就足够了 and/or 完成,当然你不需要当前套件名称的 getter 方法和套件注释。我只是扩展了你自己的例子。