Last active
August 8, 2023 10:17
-
-
Save fappel/65982e5ea7a6b2fde5a3 to your computer and use it in GitHub Desktop.
JUnit 4 TestRule to run a test in its own thread
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* RunInThread an other accompanying files are licensed under the MIT | |
* license. Copyright (C) Frank Appel 2016-2021. All rights reserved | |
*/ | |
import java.lang.annotation.ElementType; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
import java.lang.annotation.Target; | |
@Retention(RetentionPolicy.RUNTIME) | |
@Target({ElementType.METHOD}) | |
public @interface RunInThread { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* RunInThread an other accompanying files are licensed under the MIT | |
* license. Copyright (C) Frank Appel 2016-2021. All rights reserved | |
*/ | |
import org.junit.rules.TestRule; | |
import org.junit.runner.Description; | |
import org.junit.runners.model.Statement; | |
public class RunInThreadRule implements TestRule { | |
@Override | |
public Statement apply( Statement base, Description description ) { | |
Statement result = base; | |
RunInThread annotation = description.getAnnotation( RunInThread.class ); | |
if( annotation != null ) { | |
result = new RunInThreadStatement( base ); | |
} | |
return result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* RunInThread an other accompanying files are licensed under the MIT | |
* license. Copyright (C) Frank Appel 2016-2021. All rights reserved | |
*/ | |
import java.util.concurrent.ExecutionException; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
import java.util.concurrent.Future; | |
import org.junit.runners.model.Statement; | |
class RunInThreadStatement extends Statement { | |
private final Statement baseStatement; | |
private Future<?> future; | |
private volatile Throwable throwable; | |
RunInThreadStatement( Statement baseStatement ) { | |
this.baseStatement = baseStatement; | |
} | |
@Override | |
public void evaluate() throws Throwable { | |
ExecutorService executorService = runInThread(); | |
try { | |
waitTillFinished(); | |
} finally { | |
executorService.shutdown(); | |
} | |
rethrowAssertionsAndErrors(); | |
} | |
private ExecutorService runInThread() { | |
ExecutorService result = Executors.newSingleThreadExecutor(); | |
future = result.submit( new Runnable() { | |
@Override | |
public void run() { | |
try { | |
baseStatement.evaluate(); | |
} catch( Throwable throwable ) { | |
RunInThreadStatement.this.throwable = throwable; | |
} | |
} | |
} ); | |
return result; | |
} | |
private void waitTillFinished() { | |
try { | |
future.get(); | |
} catch( ExecutionException shouldNotHappen ) { | |
throw new IllegalStateException( shouldNotHappen ); | |
} catch( InterruptedException shouldNotHappen ) { | |
throw new IllegalStateException( shouldNotHappen ); | |
} | |
} | |
private void rethrowAssertionsAndErrors() throws Throwable { | |
if( throwable != null ) { | |
throw throwable; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very clear!