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

实例化对象时,它必须只允许在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();
}

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

非常感谢

最佳答案

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

  • 从来没有真正的确定性。尤其是当您寻求高精度时,测试用例将在95%的时间内成功。但是有时它们会失败,这是最难以调试的错误类型。请注意,在多线程测试用例中使用Thread.sleep()时,这甚至更加困难。
  • 带有 sleep 的测试用例需要很长时间才能运行,一段时间后,这将使您无法运行完整的测试集。

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

    不要使用真实的时钟。而是使用可以从测试用例中控制的伪时钟(模拟/ stub ):
    @Test(expected = IllegalStateException.class)
    public void testCallAfterTimeout() {
        MyObject o= new MyObject();
        // Example function that you could make
        advanceClock(1000, TimeUnit.MILLISECONDS)
        o.call();
    }
    

    在您的对象中,您必须注入(inject)一个时钟。 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() 。但是您也可以轻松实现自己的安静。

    09-30 14:31
    查看更多