Thread.sleep 在 JUnit 测试用例中

Thread.sleep in JUnit test case

我正在编写测试用例来测试对象行为。

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

我是这样设计Junit测试用例的:

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

您认为这是一种好的做法还是我应该采用其他方法?

非常感谢

不管它有什么意义,你是在自找麻烦....

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

其次,如果你想真正拥有可测试的与时间相关的功能,时间和超时应该与你的主要逻辑(MyObject class)分开处理。例如,您可以使用 Timekeeper class 和 mehtod canCallMethod() ,它由您的 MyObject class 调用(并且在其构造时设置)。通过这种方式,在您的测试中,您使用自己的 returns true 或 false 的 Timekeeper 实现初始化您的 MyObject class,并验证您的 MyObject class 是否按预期运行。 MyObject 可以具有始终使用 'real' timekeep 的默认构造函数,因此外部世界不会强制处理 Timekeeper 内部结构。

在测试用例中使用(实时)时间有两个问题:

  1. 它从来都不是真正确定性的。尤其是当您寻求高精度时,测试用例在 95% 的情况下都会成功。但有时它们会失败,这些是最难调试的失败类型。请注意,在多线程测试用例中使用 Thread.sleep() with 时,这会更加困难。
  2. 带睡眠的测试用例需要很长时间才能 运行,一段时间后这会使 运行 完整的测试集变得麻烦。

如果你必须,你的方式是可以接受的。但还有其他选择:

不要使用真正的时钟。而是使用可以从测试用例控制的假 (mocked/stubbed) 时钟:

@Test(expected = IllegalStateException.class)
public void testCallAfterTimeout() {
    MyObject o= new MyObject();
    // Example function that you could make
    advanceClock(1000, TimeUnit.MILLISECONDS)
    o.call();
}

在你的对象中你必须注入一个时钟。 MyObject 可能看起来像这样:

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.
     }
} 

在 Java 8 中提供了一个机制,例如参见 [​​=15=]。但您也可以轻松实现自己的安静。