JUnitCore Stopping

2019-07-13 12:11发布

问题:

I want to stop/destroy a running JUnitCore, which is started with

JUnitCore.run(Request.aClass(ClassToRun));

Like pleaseStop() on the RunNotifier.

Any ideas?

http://junit.sourceforge.net/javadoc/org/junit/runner/package-summary.html

回答1:

Option 1: the best option is to write your own Runner implementation, inherited from org.junit.runners.BlockJUnit4ClassRunner and declare it in your execution context, for instance as Main Class of a raw Java command line.

Get inspired of JUnit source code (it is really small), mainly org.junit.runners.ParentRunner and override the runChildren method by your own to get the opportunity to exit the execution loop when a stop command has been triggered.

The factory for Runner is Request. To start, you invoke

   (new JUnitCore()).run(Request.runner(new MyStoppableRunner().aClass(ClassToRun))

Option 2: If using your own runner is not possible in your context (launched within Eclipse for instance), thanks to a RunListener implementation registered in the used runner, you can get a reference to the thread running your test case.

If stop command has been triggered, your listener may throw a RuntimeException or even an Error in the hope it will make the original test runner collapse.

Bonus

These two options are basic as the aim is to check a stop condition and do not go on looping on methods or tests classes.

You may want to try to interrupt the test thread if stuck in sleep or wait state. To do so a watch dog thread should be created to invoke interrupt on the test thread after an inactivity timeout.



回答2:

as far as I know there 's no such method available. So the first answer should be : impossible... But with Java bytecode enhancement frameworks nothing is really impossible... So I could advise you to write a Java Interface Closeable or something like this... use the Java bytecode enhancement framework of your choice (asm, bcel, javaassist or any other) and enhance the JunitCore class to implement this interface.Once done you will be able to stop this facade for your tests...

public interface Closeable{
   public void stopMe();
}

Hi,bytecode enhancement is not the silver bullet of course....But forking and patching an Open Source project requires huge changes into your project management... Who will remeber this little patch 5 years and 3 releases later ? Adding a small class to enhance the bytecode to fulfill your needs is a pragmatic but as always not a perfect answer ....I am Ok with Yves that trying to add the feature into JUnit would be the best solution but it requires far more than technicaal knowledge... Of course you may encounter classloading weird problems while using such technique.... For integration testing I would suggest using TestNG rather than JUnit it provides many enhancements while providing a compatibility layer....

HTH Jerome



回答3:

I want to provide another simple solution to stop a JUnitCore:

JUnitCore jUnitCore = new JUnitCore();
Field field = JUnitCore.class.getDeclaredField("fNotifier");
field.setAccessible(true);
RunNotifier runNotifier = (RunNotifier) field.get(jUnitCore);
runNotifier.pleaseStop();

Credits to Matthew Farwell who transfered my idea into code.



回答4:

I needed to stop all running processes/threads as I was running executing my test suite from a main method using java -jar test.jar within a Docker image. I couldn't then extract the correct exit code after the tests had finished. I went with this:

final JUnitCore engine = new JUnitCore();
engine.addListener(new TextListener(System.out));
final Result testsResult = engine.run(AllTestSuite.class);
 if (testsResult.wasSuccessful()) {
   System.out.println("Tests complete with success!!!");
   System.exit(0);
 }
   System.out.println("Tests complete with "+ result.getFailureCount() + " failures!!!");
   System.exit(1);