【问题标题】:How to unit test code that suspends its execution without abstracting it out?如何对暂停执行的代码进行单元测试而不将其抽象出来?
【发布时间】:2015-03-03 20:40:13
【问题描述】:

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

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# Unit Testing - Thread.Sleep(x) - How to Mock the System Clock

但我确实必须验证实现是否正在等待。

您对如何为这种情况编写健壮的单元测试代码有什么建议吗?它还可能涉及重构 m() 方法。

【问题讨论】:

  • 正如你所提到的,你最好模拟时钟,你会想要在你增加时钟之前断言该函数没有被调用,然后在你增加它之后检查它是否被调用。
  • 你有什么理由不接受这个答案?

标签: java multithreading unit-testing


【解决方案1】:

处理此类问题的常用方法是使用对象等待/通知方法。这也将有助于使 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);

【讨论】:

  • 这看起来很有趣。我看到的这个解决方案的唯一问题是,由于虚假唤醒,我们应该在循环中调用 Object.wait() 并检查唤醒应该发生的条件是否为真。但在这种情况下,这个条件是:doSomeWork() 完成并且 Thread.sleep(1000) 完成。但是将其外部化并不容易。
  • 实际上主要问题是它没有验证 m() 是否确实等待了那 1 秒。这是我想在这次测试中验证的非常重要的一点。
  • 已更新以解决您的问题。您可以更进一步,使用并发包中的SemaphoreCountDownLatch 等。一切都取决于您真正需要什么。
  • 感谢您的更新。我还需要以某种方式验证该方法是否真的在 doSomeWork() 之后等待。
  • 根据需要插入更多计数器等以检查各种条件
猜你喜欢
  • 1970-01-01
  • 2011-12-19
  • 2014-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多