JUnit测试用例中的Thread.sleep

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

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

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

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

你认为这是一种好习惯还是我应该采用另一种方法?

非常感谢

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

  1. 它从来都不是确定性的。 特别是当您正在寻找高精度时,测试用例将在95%的时间内成功。 但有时它们会失败,这些是最难调试的类型。 请注意,在multithreading测试用例中使用Thread.sleep()时,这更加困难。
  2. 睡眠的测试用例需要很长时间才能运行,过了一段时间这将使运行完整的测试集变得麻烦。

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

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

 @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中提供了一种机制,例如参见LocalDate.now() 。 但你也可以轻松实现自己的安静。

无论它有什么意义,你要求麻烦….

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

其次,如果你想真正拥有可测试的与时间相关的函数,那么时间和超时应该与你的主逻辑(MyObject类)分开处理。 例如,您可以使用mehtod canCallMethod()的Timekeeper类,它由MyObject类调用(并在构造时设置)。 通过这种方式,在测试中,使用自己的Timekeeper实现初始化MyObject类,该实现返回true或false,并validationMyObject类的行为是否符合预期。 MyObject可以使用默认构造函数,它始终使用“真实”时间戳,因此外部世界不会强制处理Timekeeper内部。