95

I'm writing unit tests now. I need to simulate long-run method with Mockito to test my implementation's timeout handling. Is it possible with Mockito?

Something like this:

when(mockedService.doSomething(a, b)).thenReturn(c).after(5000L);
  • 6
    On our project we created a `DelayedAnswer` that wrapped another `Answer` and invoked it after the specified delay. This is ecentially what KL posted. – John B Oct 10 '12 at 11:44

5 Answers5

114

You could simply put the thread to sleep for the desired time. Watch out tho - such things can really slow down your automated test execution, so you might want to isolate such tests in a separate suite

It would look similar to this:

when(mock.load("a")).thenAnswer(new Answer<String>() {
   @Override
   public String answer(InvocationOnMock invocation){
     Thread.sleep(5000);
     return "ABCD1234";
   }
});
K.L.
  • 2,419
  • 1
  • 21
  • 26
  • 2
    OK, it's clear for me. But does any Mockito functionality exist for doing such things? –  Oct 10 '12 at 07:15
  • check out the edit. Im not sure its perfectly ok, but shows the idea, cant use my IDE now to confirm – K.L. Oct 10 '12 at 07:18
  • 1
    @RuslanZagirov No there isn't any timeout when you stub, however you can propose the feature on the issue tracker of mockito :) – bric3 Oct 10 '12 at 08:02
  • thanks for the fix in the edit David :) Havent played with mockito for a while, feeling a little rusty – K.L. Oct 10 '12 at 08:59
  • 7
    First call of mock.load with parameter "a" will be stubbed and result will be "cached". So subsequent invocations will not go through answer, and Thread.sleep won't be executed. – fred Nov 10 '15 at 01:16
  • 3
    See @Viswanath [2018 answer](https://stackoverflow.com/a/50530261/4188683) – Eido95 Sep 05 '18 at 12:32
  • Using Thread.sleep in a test is just generally a bad idea. It creates brittle tests that can fail unpredictably depending on environment ("Passes on my machine!") or load. Don't rely on timing (use mocks) or use libraries such as Awaitility for asynchroneous testing. – Bahadir Tasdemir Mar 18 '20 at 13:03
69

From mockito 2.8.44, org.mockito.internal.stubbing.answers.AnswersWithDelay is available for this purpose. Here's a sample usage

 doAnswer( new AnswersWithDelay( 1000,  new Returns("some-return-value")) ).when(myMock).myMockMethod();
Viswanath
  • 1,413
  • 13
  • 25
  • 4
    How would this work with a method returning void ? May be using `answerVoid()` similar to https://www.javatips.net/api/org.mockito.additionalanswers.answervoid ? – Guillaume Berche Aug 18 '21 at 16:34
  • 1
    This is internal mockito API and checkstyle complains if you use that. Do you have any other similar suggestion without explicitly adding Thread.sleep as mentioned in another answer? – Deependra Patel Oct 26 '21 at 06:21
  • 4
    [This](https://stackoverflow.com/a/59426498/1776132) answer uses the factory class `AdditionalAnswers.answersWithDelay()` which is correct way as `AnswersWithDelay` is internal class. – Smile Jan 07 '22 at 11:07
20

I created a utils for this:

import java.time.Duration;
import java.util.concurrent.TimeUnit;

import static org.mockito.Mockito.doAnswer;

public class Stubber {

    public static org.mockito.stubbing.Stubber doSleep(Duration timeUnit) {
        return doAnswer(invocationOnMock -> {
            TimeUnit.MILLISECONDS.sleep(timeUnit.toMillis());
            return null;
        });
    }

    public static <E> org.mockito.stubbing.Stubber doSleep(Duration timeUnit, E ret) {
        return doAnswer(invocationOnMock -> {
            TimeUnit.MILLISECONDS.sleep(timeUnit.toMillis());
            return ret;
        });
    }

}

and in your test case simply use:

doSleep(Duration.ofSeconds(3)).when(mock).method(anyObject());
Simon Ludwig
  • 1,754
  • 1
  • 20
  • 27
0
when(mock.mockmethod(any)).delegate.thenAnswer(
new AnswersWithDelay(
 10000000, // nanosecond
 new Returns(
     Future.Successful(Right()),
 ),

mockito-scala I implemented it with the mockito Scala plug-in. It has been tested and can sleep at a specified time

-2

Much better for Unit tests is to create method that calls actual Thread.sleep(long l) and then mock that method. With that, you can inject your test with awesome behaviour causing that your test will think it is waiting for as long as you want. With that, you can run a lot of test in blink of the eye and still testing different time-related scenario. Before using this, my UnitTest ran for six minutes. Now its under 200ms.

public class TimeTools {
public long msSince(long msStart) {
    return ((System.nanoTime() / 1_000_000) - msStart);
}

public long msNow() {
    return (System.nanoTime() / 1_000_000);
}

public Boolean napTime(long msSleep) throws InterruptedException {
    Thread.sleep(msSleep);
    return true;
}
}
-----------------------------------
@Mock
TimeTools Timetools;

@TEST
public void timeTest() {
when(timeTools.msSince(anyLong()))
            .thenReturn(0l)
            .thenReturn(5_500l)
            .thenReturn(11_000l)
            .thenReturn(11_000l)
            .thenReturn(0l)
            .thenReturn(11_000l)
            .thenReturn(11_000l)
            .thenReturn(0l)
            .thenReturn(29_000l);
}

But best approach is to inject sleeper and then mock it. So in your tests, you won't actually sleep. Then you unit tests will run fast as lightning.

Matej Lachman
  • 19
  • 1
  • 8
  • In 99% of cases when you're testing a long delay it's related to time limiters or fallbacks, which generally run through libraries measuring the actual system time. This is not helpful. – martijn p Jul 11 '23 at 07:19