0

I found the following example in JUnit documentation:

public static class HasGlobalLongTimeout {

    @Rule
    public Timeout globalTimeout= new Timeout(20);

    @Test
    public void run1() throws InterruptedException {
        Thread.sleep(100);
    }

    @Test
    public void infiniteLoop() {
        while (true) {}
    }
}

I understand that whenever JUnit tries to interrupt the first test, it will interrupt the thread where it is running on, and it will throw an InterruptedException, leading to the test being finished.

But what about the second test (infiniteLoop)? It is not throwing anything. How is it stopped after the timeout?

sapito
  • 1,472
  • 3
  • 17
  • 26

3 Answers3

1

The timeout rule runs each test in a separate thread, and waits for the timeout. After the timeout, the thread is interrupted. The test runner will then continue on to the next test. It doesn't wait for any response to the interrupt, so the test is free to continue running in the background.

infiniteLoop won't throw any InterruptedException but continue running while any remaining tests are run.

Once all the tests have finished, then the JVM running the tests will typically terminate, along with all the threads within it. Either because the threads are marked as daemon threads, or via a System.exit call.

See the source code:

fgb
  • 18,439
  • 2
  • 38
  • 52
  • I understand from your comment (and after having a look at the source code), that junit will try to join the thread with a timeout, and check if it is still running after the timeout. If it is, the test will fail. I.e., even if the test is running in the background, it will fail after the unsuccessful call to join. – sapito Jan 22 '17 at 22:35
1

I tried the following code and it works properly (i.e. both tests fails due to timeout of 20ms) I am using Java 8 and JUnit 4.12.

import java.util.concurrent.TimeUnit;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;

public class HasGlobalLongTimeout {

    @Rule
    public Timeout globalTimeout = new Timeout(20, TimeUnit.MILLISECONDS);

    @Test
    public void run1() throws InterruptedException {
        Thread.sleep(100);
    }

    @Test
    public void infiniteLoop() {
        while (true) {
        }
    }
}

Notice that I remove the static modifier in the class declaration (as far as I know it is not allowed for classes) and I changed the Timeout declaration (that one is deprecated currently).

Boni García
  • 4,618
  • 5
  • 28
  • 44
0

It should be thrown in both tests, the @Rule annotation attaches a timer to each test. If the test runs more than 20ms an exception is fired. So in your program the second test should fire an InterruptedException as well.

Aimee Borda
  • 842
  • 2
  • 11
  • 22
  • What if we had the second test alone? Would if run forever even if there is a timeout? – sapito Jan 22 '17 at 16:01
  • No it would throw the `InterrupedException` as it would still have a timeout. The annotation allows the code to localize the exception to that test, but in this case, the other test would throw another exception. – Aimee Borda Jan 22 '17 at 16:17
  • Where would this InterruptedException be thrown? It seems quite confusing to me :) It seems second test cannot throw anything at all, it is just a simple loop. – sapito Jan 22 '17 at 16:21
  • It would be thrown in both tests, the `@Rule` annotation attaches a timer to each test. If the test runs more than 20ms an exception is fired. So in your program the second test should fire an `InterruptedException` as well. – Aimee Borda Jan 22 '17 at 16:54
  • Mind explaining where the "run in sequence" is coming from? By default, JUnit does not guarantee any order for testcases, so ... well, where is it coming from? – GhostCat Jan 22 '17 at 18:37