javaspring-bootmockito

Mocking TimeUnit.MILLISECONDS.sleep() with Mockito


I want to test a method in Java 17 (springboot 3.x, Mockito 5.x) and i'm currently using mockito. This method looks like this :

public int test(){
    try {
        var test = TimeUnit.MILLISECONDS;
        test.sleep(500L);

    } catch (Exception e) {
        return 1;
    }
    return 0;

}

I want my TimeUnit.MILLISECONDS.sleep(500L) to throw an InterruptedException and thus the method will return 1. I tried many things, like this :

try(var staticMock = Mockito.mockStatic(TimeUnit.class)) {
        var mock = Mockito.mock(TimeUnit.class);
        staticMock.when(() -> mock.sleep(anyLong())).thenThrow(new InterruptedException());
    }

I also tried this :

try(var staticMock = Mockito.mockStatic(TimeUnit.class)) {

        var mock = Mockito.mock(TimeUnit.class);
        doThrow(InterruptedException.class).when(mock).sleep(anyLong());
        staticMock.when(TimeUnit::values).thenReturn(new TimeUnit[]{mock});
    }

But it won't work either -> each time the method returns 0 or there is a mockito error.

I want to specify something : I don't want to make a specific class containing TimeUnit just for testing this case. I personnaly think this is a bad pratice as it makes the code less readable for anyone not familiar with the project. And besides, understanding how to work with this case will help me also understand more Mockito (this also works if this is not possible).

Is there a way to do this just with Mockito ?


Solution

  • Instead of mocking interruption you can actually interrupt the thread. You need to do that from a different thread, but that's easily done using a ScheduledExecutorService:

    try (ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor()) {
        Thread thread = Thread.currentThread();
    
        executor.schedule(thread::interrupt, 1, TimeUnit.SECONDS);
    
        assertThrows(InterruptedException.class, () -> TimeUnit.SECONDS.sleep(2));
    }