我可以用 Mockito 延迟存根方法响应吗?

我现在正在编写单元测试。我需要用 Mockito 模拟长期运行方法来测试我的实现的超时处理。莫基托有可能吗?

就像这样:

when(mockedService.doSomething(a, b)).thenReturn(c).after(5000L);
59781 次浏览

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";
}
});

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());

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.

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();
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