在没有显式测试套件 类 声明的情况下清理所有 JUnit 测试
Cleaning up after all JUnit tests without explicit test suite classes declaration
在 Intelij 和 Eclipse IDE(可能还有其他一些)中,可以 运行 包中的所有测试 classes(甚至项目中的所有测试 classes ) 而无需将它们中的每一个明确地放在测试套件 class 中(this 是我想避免的)。只需右键单击 -> 运行 所有测试,瞧瞧!
虽然我对这种测试方法有一个问题。我想在所有测试完成后做一些清理工作,但无论我做什么,似乎都没有任何效果。
起初,我尝试使用 RunListener and its testRunFinished() 方法,但在每次原子测试完成后都会调用它,所以当 运行 中有很多时,这不是我想要的。
然后我想到了终结器和 runFinalizersOnExit(true),不幸的是,它已被弃用并且只能在其中一台执行测试的计算机上工作。
我尝试的最后一件事是创建一个 "listener" 线程,该线程 - 给定测试执行开始和结束时间差异 - 例如,在测试完成五秒后进行清理。我使用下面的代码来测试该解决方案:
import org.junit.Test;
public class Main {
static {
System.out.println("In a static block!");
new Thread(new Runnable() {
public void run() {
System.out.println("Starting static thread!");
try {
while (true) {
Thread.sleep(1000);
System.out.println("Static thread working...");
}
} catch (InterruptedException e) {
System.err.println("Static thread interrupted!");
e.printStackTrace();
} catch (Exception e) {
System.err.println("Static thread catches exception!");
e.printStackTrace();
} finally {
System.err.println("Static thread in finally method.");
Thread.currentThread().interrupt();
}
}
}).start();
System.out.println("Exiting static block!");
}
@Test
public void test() throws Exception {
System.out.println("Running test!");
Thread.sleep(3000);
System.out.println("Stopping test!");
}
}
运气不好。测试完成后线程被杀死。甚至 finally 块也永远不会执行...
In a static block!
Exiting static block!
Running test!
Starting static thread!
Static thread working...
Static thread working...
Stopping test!
Static thread working...
期望的行为是:
- 右击
- 运行 所有测试
- TestA 是 运行宁...
- 测试A完成
- 测试 B 是 运行宁...
- 测试 B 完成
- ... 更多测试 classes...
- 清理
不确定我是否完全理解您的问题,但我认为您需要 before、beforeClass、after 和 afterClass 方法。即
@BeforeClass
public void beforeClass() {
// Do stuff before test class is run
}
@Before
public void before() {
// Do stuff before each test is run
}
@After
public void after() {
// DO stuff after each test is run
}
@AfterClass
public void afterClass() {
// DO stuff after test class is run
}
您可以使用一些黑客技术或其他框架在更全球化的层面上做事。例如 Spring 的测试套件。但我会尽量将这些事情保持在单个测试的范围内 class.
我找到了解决问题的办法。我的同事建议 "hey, can't you just count the test classes?" - 我就是这么做的。
这里使用了一点反射魔法,所以代码可能不可移植:
public abstract class CleaningTestRunner extends BlockJUnit4ClassRunner {
protected abstract void cleanupAfterAllTestRuns();
private static long TEST_CLASSES_AMOUNT;
private static long TEST_RUNS_FINISHED = 0;
private static boolean CLASSES_COUNTED = false;
static {
while (!CLASSES_COUNTED) {
try {
Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
Vector<Class> classes = (Vector<Class>) f.get(CleaningTestRunner.class.getClassLoader());
TEST_CLASSES_AMOUNT = 0;
for (Class<?> klass : classes) {
if (klass.isAnnotationPresent(RunWith.class)) {
if (CleaningTestRunner.class.isAssignableFrom(klass.getAnnotation(RunWith.class).value())) {
for (Method method : klass.getMethods()) {
if (method.isAnnotationPresent(Test.class)) {
++TEST_CLASSES_AMOUNT;
break;
}
}
}
}
}
CLASSES_COUNTED = true;
} catch (Exception ignored) {
}
}
}
public CleaningTestRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
public void run(RunNotifier notifier) {
notifier.addListener(new TestCleanupListener());
super.run(notifier);
}
private class TestCleanupListener extends RunListener {
@Override
public void testRunFinished(Result result) throws Exception {
++TEST_RUNS_FINISHED;
if (TEST_RUNS_FINISHED == TEST_CLASSES_AMOUNT) {
cleanupAfterAllTestRuns();
}
}
}
}
在 Intelij 和 Eclipse IDE(可能还有其他一些)中,可以 运行 包中的所有测试 classes(甚至项目中的所有测试 classes ) 而无需将它们中的每一个明确地放在测试套件 class 中(this 是我想避免的)。只需右键单击 -> 运行 所有测试,瞧瞧!
虽然我对这种测试方法有一个问题。我想在所有测试完成后做一些清理工作,但无论我做什么,似乎都没有任何效果。
起初,我尝试使用 RunListener and its testRunFinished() 方法,但在每次原子测试完成后都会调用它,所以当 运行 中有很多时,这不是我想要的。
然后我想到了终结器和 runFinalizersOnExit(true),不幸的是,它已被弃用并且只能在其中一台执行测试的计算机上工作。
我尝试的最后一件事是创建一个 "listener" 线程,该线程 - 给定测试执行开始和结束时间差异 - 例如,在测试完成五秒后进行清理。我使用下面的代码来测试该解决方案:
import org.junit.Test;
public class Main {
static {
System.out.println("In a static block!");
new Thread(new Runnable() {
public void run() {
System.out.println("Starting static thread!");
try {
while (true) {
Thread.sleep(1000);
System.out.println("Static thread working...");
}
} catch (InterruptedException e) {
System.err.println("Static thread interrupted!");
e.printStackTrace();
} catch (Exception e) {
System.err.println("Static thread catches exception!");
e.printStackTrace();
} finally {
System.err.println("Static thread in finally method.");
Thread.currentThread().interrupt();
}
}
}).start();
System.out.println("Exiting static block!");
}
@Test
public void test() throws Exception {
System.out.println("Running test!");
Thread.sleep(3000);
System.out.println("Stopping test!");
}
}
运气不好。测试完成后线程被杀死。甚至 finally 块也永远不会执行...
In a static block!
Exiting static block!
Running test!
Starting static thread!
Static thread working...
Static thread working...
Stopping test!
Static thread working...
期望的行为是:
- 右击
- 运行 所有测试
- TestA 是 运行宁...
- 测试A完成
- 测试 B 是 运行宁...
- 测试 B 完成
- ... 更多测试 classes...
- 清理
不确定我是否完全理解您的问题,但我认为您需要 before、beforeClass、after 和 afterClass 方法。即
@BeforeClass
public void beforeClass() {
// Do stuff before test class is run
}
@Before
public void before() {
// Do stuff before each test is run
}
@After
public void after() {
// DO stuff after each test is run
}
@AfterClass
public void afterClass() {
// DO stuff after test class is run
}
您可以使用一些黑客技术或其他框架在更全球化的层面上做事。例如 Spring 的测试套件。但我会尽量将这些事情保持在单个测试的范围内 class.
我找到了解决问题的办法。我的同事建议 "hey, can't you just count the test classes?" - 我就是这么做的。
这里使用了一点反射魔法,所以代码可能不可移植:
public abstract class CleaningTestRunner extends BlockJUnit4ClassRunner {
protected abstract void cleanupAfterAllTestRuns();
private static long TEST_CLASSES_AMOUNT;
private static long TEST_RUNS_FINISHED = 0;
private static boolean CLASSES_COUNTED = false;
static {
while (!CLASSES_COUNTED) {
try {
Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
Vector<Class> classes = (Vector<Class>) f.get(CleaningTestRunner.class.getClassLoader());
TEST_CLASSES_AMOUNT = 0;
for (Class<?> klass : classes) {
if (klass.isAnnotationPresent(RunWith.class)) {
if (CleaningTestRunner.class.isAssignableFrom(klass.getAnnotation(RunWith.class).value())) {
for (Method method : klass.getMethods()) {
if (method.isAnnotationPresent(Test.class)) {
++TEST_CLASSES_AMOUNT;
break;
}
}
}
}
}
CLASSES_COUNTED = true;
} catch (Exception ignored) {
}
}
}
public CleaningTestRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
public void run(RunNotifier notifier) {
notifier.addListener(new TestCleanupListener());
super.run(notifier);
}
private class TestCleanupListener extends RunListener {
@Override
public void testRunFinished(Result result) throws Exception {
++TEST_RUNS_FINISHED;
if (TEST_RUNS_FINISHED == TEST_CLASSES_AMOUNT) {
cleanupAfterAllTestRuns();
}
}
}
}