Thread.sleep in JUnit测试用例

apeeds0o  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(198)

我正在写一个测试用例来测试一个对象的行为。
当对象被示例化时,它必须允许调用一个方法,比如说call(),只有在500 ms内被调用,否则它必须抛出一个异常。
我设计的Junit测试用例是这样的:

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

字符串
你认为这是一个很好的做法,还是我应该遵循另一种方法?
非常感谢

u0sqgete

u0sqgete1#

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

@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()。但你也可以很容易地实现自己的机制。

gmol1639

gmol16392#

不管这是什么意思,你是在自找麻烦......
如果你决定超时需要在60分钟后发生,你会等你的测试一个小时吗?超时应该是你的MyObject的参数,这样你就可以设置它为一些小的值进行测试(或者甚至设置为0来强制测试时总是超时)。
其次,如果你想真正拥有可测试的时间相关函数,时间和超时应该与你的主逻辑分开处理(MyObject类)。例如,您可以让Timekeeper类具有由MyObject类调用的方法canCallMethod()(它是建立在它的结构上的)。这样在你的测试中,您可以使用自己的Timekeeper实现初始化MyObject类,该实现返回true或false,并验证MyObject类的行为是否符合预期。MyObject可以具有始终使用“真实的”计时的默认构造函数,以便外部世界不是强迫你去对付时间守护者内部的人

相关问题