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 内部结构。
在测试用例中使用(实时)时间有两个问题:
- 它从来都不是真正确定性的。尤其是当您寻求高精度时,测试用例在 95% 的情况下都会成功。但有时它们会失败,这些是最难调试的失败类型。请注意,在多线程测试用例中使用
Thread.sleep()
with 时,这会更加困难。
- 带睡眠的测试用例需要很长时间才能 运行,一段时间后这会使 运行 完整的测试集变得麻烦。
如果你必须,你的方式是可以接受的。但还有其他选择:
不要使用真正的时钟。而是使用可以从测试用例控制的假 (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=]。但您也可以轻松实现自己的安静。
我正在编写测试用例来测试对象行为。
当对象被实例化时,它必须允许调用一个方法,比如 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 内部结构。
在测试用例中使用(实时)时间有两个问题:
- 它从来都不是真正确定性的。尤其是当您寻求高精度时,测试用例在 95% 的情况下都会成功。但有时它们会失败,这些是最难调试的失败类型。请注意,在多线程测试用例中使用
Thread.sleep()
with 时,这会更加困难。 - 带睡眠的测试用例需要很长时间才能 运行,一段时间后这会使 运行 完整的测试集变得麻烦。
如果你必须,你的方式是可以接受的。但还有其他选择:
不要使用真正的时钟。而是使用可以从测试用例控制的假 (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=]。但您也可以轻松实现自己的安静。