如何对挂起执行而不将其抽象出来的代码进行单元测试



我必须对一个暂停执行(定期执行一些工作)的方法进行单元测试:

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);

最新更新