Java JUnit测试用例中的Thread.sleep

Java JUnit测试用例中的Thread.sleep,java,junit,Java,Junit,我正在写一个测试用例来测试一个对象的行为 当对象被实例化时,它必须仅在500毫秒内被调用时才允许调用方法,比如call(),否则它必须抛出异常 我将Junit测试用例设计为: @Test(expected = IllegalStateException.class) public void testCallAfterTimeout() { MyObject o= new MyObject(); //To ensure the timeout is occurred Thr

我正在写一个测试用例来测试一个对象的行为

当对象被实例化时,它必须仅在500毫秒内被调用时才允许调用方法,比如call(),否则它必须抛出异常

我将Junit测试用例设计为:

@Test(expected = IllegalStateException.class)
public void testCallAfterTimeout() {
    MyObject o= new MyObject();
    //To ensure the timeout is occurred
    Thread.sleep(1000);
    o.call();
}
class MyObject
{

     public MyObject()
     {
           this(new Clock());
     }

     // Protected so only the test case can access it
     protected MyObject(Clock clock)
     {
           // Save clock as local variable, store creation time etc.
     }
} 
你认为这是一个好的做法还是我应该遵循另一种方法


非常感谢

不管这有什么意义,也不管你是在自找麻烦

如果您决定60分钟后需要超时,您会等待测试一小时吗? 超时应该是MyObject的参数,因此您可以将其设置为某个小值以进行测试(甚至可以设置为0以在测试时强制alwyas超时)

其次,如果您真的想拥有可测试的时间相关函数,那么时间和超时应该与主逻辑(MyObject类)分开处理。例如,可以使用Method canCallMethod()创建Timekeeper类,该类由MyObject类调用(并在构造时设置)。通过这种方式,在测试中,您可以使用自己的计时器实现初始化MyObject类,该计时器实现返回true或false,并验证MyObject类的行为是否符合预期。
MyObject可以具有始终使用“实时”计时器的默认构造函数,这样外部世界就不会被迫处理计时器内部。在测试用例中使用(实时)时间有两个问题:

  • 它从来都不是确定的。特别是当您寻求高精度时,测试用例将在95%的时间内成功。但有时它们会失败,这是最难调试的失败类型。请注意,在多线程测试用例中使用
    Thread.sleep()
    时,这甚至更加困难
  • 带有休眠的测试用例需要很长时间才能运行,过一段时间后,这将使运行完整的测试集变得很麻烦
  • 如果你必须这样做,你的方式是可以接受的。但还有其他选择:

    不要使用真正的时钟。相反,使用一个可以从测试用例中控制的假(模拟/存根)时钟:

    @Test(expected = IllegalStateException.class)
    public void testCallAfterTimeout() {
        MyObject o= new MyObject();
        // Example function that you could make
        advanceClock(1000, TimeUnit.MILLISECONDS)
        o.call();
    }
    
    在你的对象中,你必须注入一个时钟<代码>MyObject可能如下所示:

    @Test(expected = IllegalStateException.class)
    public void testCallAfterTimeout() {
        MyObject o= new MyObject();
        //To ensure the timeout is occurred
        Thread.sleep(1000);
        o.call();
    }
    
    class MyObject
    {
    
         public MyObject()
         {
               this(new Clock());
         }
    
         // Protected so only the test case can access it
         protected MyObject(Clock clock)
         {
               // Save clock as local variable, store creation time etc.
         }
    } 
    

    在Java8中提供了一种机制,请参见示例。但您也可以轻松实现自己的安静

    为什么首先要这样做?如果您真的想测试这个特定的需求,您将很难找到更好的方法。可能您可以配置超时,并使用最短的测试时间。正如上面所暗示的,一个问题是为什么您的其他对象会这样做?但撇开这一点不谈,这种方法似乎很好,尽管它的粒度相当粗;1000毫秒比500毫秒长得多,如果我删除系统时钟的隐式依赖关系,用一个“可存根的”时钟替换,时间会立即流逝呢?考虑到当前的模拟框架,这似乎过于工程化了。简单地提供一个受保护的方法就足以模拟它进行测试。这是个人喜好,但我不喜欢部分模拟,因为被测试对象的模拟方法感觉是错误的,并建议将这种逻辑委托给其他地方==过度工程化。我认为测试应该从务实的角度进行:让测试关注部分的复杂性预算,但一定要将其保持在最低限度。因此,如果有机会在测试对象内部模拟出一种策略方法,那么一定要抓住它。请记住,复杂性本身会导致维护和正确性问题,而测试正是为了保护您免受这些问题的影响。