Java 使用 Thread.sleep 进行测试
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1868637/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Testing with Thread.sleep
提问by notnoop
What are the recommended approaches to using Thread.sleep()
to speed up tests.
Thread.sleep()
用于加速测试的推荐方法是什么。
I am testing a network library with a retry functionality when connections are dropped or timeout errors occur, etc. The library however, uses a Thread.sleep()
between the retries (so it won't connect thousands times while the server is restarting). The call is slowing the unit tests significantly, and I wonder what the options are to override it.
我正在测试具有重试功能的网络库,当连接断开或发生超时错误等。但是,该库Thread.sleep()
在重试之间使用 a (因此在服务器重新启动时它不会连接数千次)。该调用显着减慢了单元测试,我想知道有哪些选项可以覆盖它。
Note, I'm open to actually changing the code, or using a mocking framework to mock Thread.sleep(), but would like to hear your opinions/recommendation first.
请注意,我愿意实际更改代码,或使用模拟框架来模拟 Thread.sleep(),但想先听听您的意见/建议。
采纳答案by Eugene Kuleshov
It is usually a good idea to delegate time-related functionality to a separate component. That include getting the current time, as well as delays like Thread.sleep(). This way it is easy to substitute this component with mock during testing, as well as switch to a different implementation.
将与时间相关的功能委托给单独的组件通常是一个好主意。这包括获取当前时间,以及像 Thread.sleep() 这样的延迟。这样,在测试期间很容易用模拟替换这个组件,以及切换到不同的实现。
回答by Bozho
Make the sleeping time configurable through a setter, and provide a default value. So in your unit tests, call the setter with a small argument (1 for example), and then execute the method that would call Thread.sleep()
.
通过设置器使睡眠时间可配置,并提供默认值。因此,在您的单元测试中,使用一个小参数(例如 1)调用 setter,然后执行将调用Thread.sleep()
.
Another similar approach is to make if configurable via a boolean, so that Thread.sleep()
isn't called at all if the boolean
is set to false
.
另一种类似的方法是通过布尔值设置Thread.sleep()
if ,因此如果boolean
设置为,则根本不会调用它false
。
回答by Greg Mattes
Create some retry delay type that represents the policy for retry delays. Invoke some method on the policy type for the delay. Mock it as you like. No conditional logic, or true
/false
flags. Just inject the type that you want.
创建一些表示重试延迟策略的重试延迟类型。对延迟的策略类型调用一些方法。随心所欲地嘲笑它。没有条件逻辑或true
/false
标志。只需注入您想要的类型。
In ConnectRetryPolicy.java
在 ConnectRetryPolicy.java 中
public interface ConnectRetryPolicy {
void doRetryDelay();
}
In SleepConnectRetryPolicy.java
在 SleepConnectRetryPolicy.java 中
public class final SleepConnectRetryPolicy implements ConnectRetryPolicy {
private final int delay;
public SleepConnectRetryPolicy(final int delay) {
this.delay = delay;
}
@Override
public void doRetryDelay() {
try {
Thread.sleep(delay);
} catch (InterruptedException ie) {
log.error("connection delay sleep interrupted", ie);
}
}
}
In MockConnectRetryPolicy.java
在 MockConnectRetryPolicy.java 中
public final class MockConnectRetryPolicy implements ConnectRetryPolicy {
@Override
public void doRetryDelay() {
// no delay
}
}
回答by Blundell
Eugene is right, make your own component to wrap the system that is out of your control Just done this myself thought I'd share, this is known as 'SelfShunt' check this out:
Eugene 是对的,制作您自己的组件来包装不受您控制的系统我自己刚刚完成了这个我想我会分享,这被称为“ SelfShunt”检查一下:
Generator
is a class that when you call getId()
it returns the current system time.
Generator
是一个类,当您调用getId()
它时返回当前系统时间。
public class GeneratorTests implements SystemTime {
private Generator cut;
private long currentSystemTime;
@Before
public void setup(){
cut = Generator.getInstance(this);
}
@Test
public void testGetId_returnedUniqueId(){
currentSystemTime = 123;
String id = cut.getId();
assertTrue(id.equals("123"));
}
@Override
public long currentTimeMillis() {
return currentSystemTime;
}
}
We make the test class 'SelfShunt' and become the SystemTime component that way we have full control of what the time is.
我们将测试类设为“SelfShunt”并成为 SystemTime 组件,这样我们就可以完全控制时间。
public class BlundellSystemTime implements SystemTime {
@Override
public long currentTimeMillis(){
return System.currentTimeMillis();
}
}
We wrap the component that isn't under our control.
我们包装了不受我们控制的组件。
public interface SystemTime {
long currentTimeMillis();
}
Then make an interface so our test can 'SelfShunt'
然后制作一个接口,以便我们的测试可以“SelfShunt”
回答by Big Kahuna
I would argue why are you trying to test Thread.sleep. It seems to be me you're trying to test the behaviour as a consequence of some event.
我会争论你为什么要测试 Thread.sleep。似乎是我您试图测试由于某些事件而导致的行为。
i.e. what happens if:
即,如果:
- connection timeout
- connection dropped
- 连接超时
- 连接断开
If you model code based on events then you can test what should happen should a particular event occurred rather than having to come up with a construct that masks the concurrent API calls. Else what are you really testing? Are you testing how your application reacts to different stimuli or simply testing the JVM is working correctly?
如果您基于事件对代码进行建模,那么您可以测试在特定事件发生时应该发生什么,而不必提出屏蔽并发 API 调用的构造。否则你真正在测试什么?您是在测试您的应用程序如何对不同的刺激做出反应,还是只是在测试 JVM 是否正常工作?
I agree with the other readers that sometimes it's useful to put an abstraction around any code time or thread related i.e. Virtual clock http://c2.com/cgi/wiki?VirtualClockso you can mock out any timing/concurrent behaviour and concentrate on the behaviour of the unit itself.
我同意其他读者的看法,有时将任何代码时间或线程相关的抽象化是有用的,即虚拟时钟http://c2.com/cgi/wiki?VirtualClock这样您就可以模拟任何时间/并发行为并专注于单元本身的行为。
It also sounds like you should adopt a state pattern so you object has specific behaviour depending on what state it's in. i.e AwaitingConnectionState, ConnectionDroppedState. Transition to different states would be via the different events i.e. timeout, dropped connection etc. Not sure if this overkill for your needs but it certainly removes a lot of conditional logic which can make the code more complicated and unclear.
听起来您也应该采用状态模式,以便您的对象根据它所处的状态具有特定的行为。即 AwaitingConnectionState、ConnectionDroppedState。转换到不同状态将通过不同的事件,即超时、断开的连接等。不确定这是否满足您的需求,但它肯定会删除许多条件逻辑,这些逻辑会使代码更加复杂和不清楚。
If you approach this way, then you can still test behaviour at the unit level whilst still testing in situ with an integration test or acceptance test later.
如果您采用这种方式,那么您仍然可以在单元级别测试行为,同时仍然可以在稍后使用集成测试或验收测试进行原位测试。
回答by Wim Deblauwe
I just faced a similar issue and I created a Sleeper
interface to abstract this away:
我刚刚遇到了类似的问题,我创建了一个Sleeper
接口来抽象它:
public interface Sleeper
{
void sleep( long millis ) throws InterruptedException;
}
The default implementation uses Thread.sleep()
:
默认实现使用Thread.sleep()
:
public class ThreadSleeper implements Sleeper
{
@Override
public void sleep( long millis ) throws InterruptedException
{
Thread.sleep( millis );
}
}
In my unit tests, I inject a FixedDateTimeAdvanceSleeper
:
在我的单元测试中,我注入了一个FixedDateTimeAdvanceSleeper
:
public class FixedDateTimeAdvanceSleeper implements Sleeper
{
@Override
public void sleep( long millis ) throws InterruptedException
{
DateTimeUtils.setCurrentMillisFixed( DateTime.now().getMillis() + millis );
}
}
This allows me to query the time in a unit test:
这允许我在单元测试中查询时间:
assertThat( new DateTime( DateTimeUtils.currentTimeMillis() ) ).isEqualTo( new DateTime( "2014-03-27T00:00:30" ) );
Note that you need to fix the time first using DateTimeUtils.setCurrentMillisFixed( new DateTime( "2014-03-26T09:37:13" ).getMillis() );
at the start of your test and restore the time again after the test using DateTimeUtils.setCurrentMillisSystem();
请注意,您需要DateTimeUtils.setCurrentMillisFixed( new DateTime( "2014-03-26T09:37:13" ).getMillis() );
在测试开始时首先使用修复时间,并在测试后使用DateTimeUtils.setCurrentMillisSystem();