Java 使用Thread.sleep进行测试

Java 使用Thread.sleep进行测试,java,unit-testing,testing,sleep,Java,Unit Testing,Testing,Sleep,使用Thread.sleep()加速测试的推荐方法有哪些 我正在测试一个具有重试功能的网络库,当连接断开或出现超时错误时,等等。但是,该库在重试之间使用Thread.sleep()(因此在服务器重新启动时,它不会连接数千次)。这个调用大大降低了单元测试的速度,我想知道覆盖它的选项是什么 注意,我愿意实际更改代码,或者使用模拟框架来模拟Thread.sleep(),但希望先听听您的意见/建议。通过setter设置睡眠时间,并提供默认值。因此,在单元测试中,使用一个小参数(例如1)调用setter,

使用
Thread.sleep()
加速测试的推荐方法有哪些

我正在测试一个具有重试功能的网络库,当连接断开或出现超时错误时,等等。但是,该库在重试之间使用
Thread.sleep()
(因此在服务器重新启动时,它不会连接数千次)。这个调用大大降低了单元测试的速度,我想知道覆盖它的选项是什么


注意,我愿意实际更改代码,或者使用模拟框架来模拟Thread.sleep(),但希望先听听您的意见/建议。

通过setter设置睡眠时间,并提供默认值。因此,在单元测试中,使用一个小参数(例如1)调用setter,然后执行调用
Thread.sleep()
的方法


另一种类似的方法是通过布尔值使if可配置,这样,如果
布尔值设置为
false
,则根本不会调用
Thread.sleep()
,创建一些表示重试延迟策略的重试延迟类型。为延迟调用策略类型上的某些方法。随便你怎么嘲笑。无条件逻辑或
true
/
false
标志。只需注入您想要的类型

在ConnectRetryPolicy.java中

public interface ConnectRetryPolicy {
    void doRetryDelay();
}
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);
        }
    }
}
public final class MockConnectRetryPolicy implements ConnectRetryPolicy {    
    @Override
    public void doRetryDelay() {
        // no delay
    }
}
在SleepConnectRetryPolicy.java中

public interface ConnectRetryPolicy {
    void doRetryDelay();
}
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);
        }
    }
}
public final class MockConnectRetryPolicy implements ConnectRetryPolicy {    
    @Override
    public void doRetryDelay() {
        // no delay
    }
}
在MockConnectRetryPolicy.java中

public interface ConnectRetryPolicy {
    void doRetryDelay();
}
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);
        }
    }
}
public final class MockConnectRetryPolicy implements ConnectRetryPolicy {    
    @Override
    public void doRetryDelay() {
        // no delay
    }
}

将与时间相关的功能委托给单独的组件通常是一个好主意。这包括获取当前时间,以及诸如Thread.sleep()之类的延迟。通过这种方式,在测试期间可以很容易地用mock替换此组件,并切换到其他实现。

Eugene是对的,制作您自己的组件来包装您无法控制的系统刚才我自己做了这件事,我想与大家分享一下,这就是所谓的“检查一下:

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;
    }
}
我们使测试类成为“自分流”,并成为系统时间组件,这样我们就可以完全控制时间

public class BlundellSystemTime implements SystemTime {

    @Override
    public long currentTimeMillis(){
        return System.currentTimeMillis();
    }
}
我们包装不在我们控制之下的组件

public interface SystemTime {

    long currentTimeMillis();

}

然后制作一个接口,这样我们的测试就可以“自分流”

我想问一下为什么要测试Thread.sleep。似乎是我,你试图测试某个事件的后果

i、 e.如果:

  • 连接超时
  • 断开连接
如果您基于事件对代码进行建模,那么您可以测试在发生特定事件时应该发生什么,而不必提出屏蔽并发API调用的构造。你到底在测试什么?您是在测试应用程序对不同刺激的反应,还是只是测试JVM是否正常工作

我同意其他读者的观点,即有时在任何代码时间或线程相关的时间(即虚拟时钟)周围放置一个抽象是有用的,这样您就可以模拟任何计时/并发行为,并专注于单元本身的行为

听起来您还应该采用一种状态模式,以便根据对象所处的状态,对象具有特定的行为。i、 e等待连接状态,连接状态。转换到不同的状态将通过不同的事件进行,例如超时、断开连接等。不确定这是否满足您的需要,但它肯定会删除许多条件逻辑,从而使代码更加复杂和不清楚


如果您采用这种方法,那么您仍然可以在单元级别测试行为,同时仍然可以稍后通过集成测试或验收测试进行现场测试

我刚刚遇到了一个类似的问题,我创建了一个
Sleeper
接口来抽象这个问题:

public interface Sleeper
{
    void sleep( long millis ) throws InterruptedException;
}
默认实现使用
Thread.sleep()

在我的单元测试中,我注入了一个
FixedDateTimeAdvanceSleeper

public class FixedDateTimeAdvanceSleeper implements Sleeper
{
    @Override
    public void sleep( long millis ) throws InterruptedException
    {
        DateTimeUtils.setCurrentMillisFixed( DateTime.now().getMillis() + millis );
    }
}
这允许我查询单元测试中的时间:

assertThat( new DateTime( DateTimeUtils.currentTimeMillis() ) ).isEqualTo( new DateTime( "2014-03-27T00:00:30" ) );

请注意,您需要首先使用
DateTimeUtils.setCurrentMillisFixed(new DateTime(“2014-03-26T09:37:13”).getMillis()修复时间并使用
DateTimeUtils.setCurrentMillisSystem()在测试后再次恢复时间

我一直想创建一个
机器
类来抽象掉所有这些。通过这种方式,您还可以在一个地方设置配置,甚至可以跳过任何您想要的内容,而不是通过代码传播这种逻辑。@notnoop正是我使用
时钟
类所做的。支持基本操作,如
Clock.now()
Clock.freeze()
Clock.freeze(pointInTime)
等。没有组件直接与运行时交互以获取时间,而是通过
时钟
。这可以看作是模拟单元测试的案例研究。不要使用Thread.sleep(),使用wait()方法。Thread.sleep()使用CPU周期,而wait()不使用。这不仅仅是一个策略,而是一个可配置的睡眠执行器。策略只代表围绕睡眠的策略,而不是执行它。对于其余部分,这是一个好主意。如果我不想为了测试而将我的内部配置暴露给外部,该怎么办?