问题
In Intelij and Eclipse IDEs (and probably some others too) it's possible to run all test classes from a package (or even all test classes in a project) without the need to put each of them explicitly in a test suite class (this is something I want to avoid). Just right click -> run all tests and voilà!
I've got one problem with that approach to testing though. I want to do some cleaning up after all the tests are done, but no matter what I do, nothing seems to work.
At first, I tried using RunListener and its testRunFinished() method, but it is called after every atomic test is done, so not what I want when running many of them.
Then I thought about finalizers and runFinalizersOnExit(true), unfortunatelly, it is deprecated and worked only on one of computers that tests are executed on.
Last thing I tried was to create a "listener" thread, that - given tests execution start and end time differences - would clean up, for instance, after five seconds of test completion. I used code below to test that solution:
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!");
}
}
With no luck. The thread is killed after the test is done. And even the finally block is never executed...
In a static block!
Exiting static block!
Running test!
Starting static thread!
Static thread working...
Static thread working...
Stopping test!
Static thread working...
Desired behavior would be:
- right click
- run all tests
- TestA is running...
- TestA done
- TestB is running...
- TestB done
- ... more test classes...
- cleanup
回答1:
Not sure if I fully have your question right, but I think you want before, beforeClass, after and afterClass methods. i.e.
@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
}
You can do things on a more global level with some hacking or other frameworks. Spring's test suites for example. But I would try to keep such things within the scope of a single test class.
回答2:
I've found a solution to my problem. My colleague suggested "hey, can't you just count the test classes?" - and that's what I did.
A little bit of reflection magic is used here, so the code might not be portable:
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();
}
}
}
}
来源:https://stackoverflow.com/questions/37472881/cleaning-up-after-all-junit-tests-without-explicit-test-suite-classes-declaratio