我必须对一个暂停执行(定期执行一些工作)的方法进行单元测试:
void m() {
do {
doSomeWork();
Thread.sleep(1000);
} while (condition);
}
我要测试的是多次while循环执行,并检查doSomeWork()是否正确执行。所以目前我的测试是这样的:
1) 在新线程中开始执行m()。
2) 在主线程中:thread.sleep(1000+200);
3) 在主线程中断言工作已正确完成。
4) 在主线程中:thread.sleep(1000+200);
5) 在主线程中断言工作已正确完成。
6) 以及一次4和5
问题是,不同机器上的doSomeWork()需要不同的时间,而且很难找到一个好的值来等待测试。
对于这种情况,我看到了一种常见的方法,那就是提取睡眠时间,在测试代码中不要等待:C#单元测试-线程.睡眠(x)-如何模拟系统时钟
但我真的必须核实一下,实施正在等待中。
你对如何为这种场景编写健壮的单元测试代码有什么建议吗?它还可以涉及对m()方法的重构。
处理类似问题的常见方法是使用对象等待/通知方法。这也将有助于使方法m()
在其他上下文中更可用。这样的实现:
void m() {
do {
doSomeWork();
Thread.sleep(1000);
synchronized (this) {
this.notifyAll();
}
} while (condition);
}
然后在你的测试课上,你可以做:
...
synchronized (obj) {
obj.wait(10000);
}
等待中的10000
只是用于类的超时。这可以防止m
的重构(或等效的错误)导致测试超时。
当然,这个建议需要一些对象来用于互斥对象。我为m选择了类本身,但任何对象都可以使用。有时我只是为这种类型的用途创建一个对象:Object mutex = new Object()
如果你需要确保工作和睡眠成功,那么你也可以使用AtomicInteger作为计数器:
AtomicInteger counter = new AtomicInteger(0);
void m() {
do {
doSomeWork();
Thread.sleep(1000);
counter.incrementAndGet()
synchronized (counter) {
counter.notifyAll();
}
} while (condition);
}
然后在你的测试类中,你可以做(为了简单起见,缺少适当的方法):
...
synchronized (obj.counter) {
obj.counter.wait(10000);
}
assert(obj.counter.get() > 0);