TDD:测试等待功能

TDD: test wait functionality

我有一个 class Foo,带有类似锁定机制的东西。我们将这些方法称为 lock()unlock()waitUntilUnlocked()。这些方法的实现不感兴趣,因为我想测试它们(TDD)。

现在我想写一个测试 waitUntilUnlocked() 真的等到 unlock() 被调用。我想出的想法如下:

@Test
public void waitUntilUnlocked_waits() {
    final Foo foo = createFoo();
    final long[] durationInThread = new long[1];

    foo.lock();
    inThread(() -> {
        durationInThread[0] = measureDurationOf(this::sleepSomeTime);
        foo.unlock();
    });

    final long waitingTime = measureDurationOf(foo::waitUntilUnlocked);

    assertThat(waitingTime).isGreaterThanOrEqualTo(durationInThread[0]);
}

缺点:这与 sleep() 一起使用会导致速度变慢。此外,我有时会得到奇怪的结果,即断言 不符合 (睡眠时间为 500 毫秒,durationInThread[0] 为 501 毫秒,waitingTime 为 498 毫秒)。

对于 reliablefast 测试,您有更好的想法吗?

我们的想法是编写一个测试,如果你的锁是假的,它最终会失败,但是当涉及到同步时,没有一个快速可靠的黑盒测试.

想象一下另一个人,一个自由职业者,正在写 waitUntilUnlocked()。他懒洋洋地决定把它写成

waitUntilUnlocked()
{
    //haha I know they cannot lock for more than 10 sec, easy money
    Thread.sleep(10*1000);
}

您的测试将通过。您正在尝试测试 waitUntilUnlocked() 的调用者将等待 永远 ,这是无法测试的。

更简单的测试方法是结合这两个测试。

第一个是您的测试有点简化。它测试线程确实等待至少一段时间时被锁定。

final Foo foo = createFoo();

foo.lock();
inThread(() -> {
        foo.waitUntilUnlocked();
    });
long time_millisec = 100;
inThread.join(time_millisec);
bool success = inThread.isAlive(); 

它永远不会解锁。 time_millisec 是你的参数。无需测量时间。

第二个测试线程在解锁后是否取得进展。您可以添加一个计时器来测量连接完成前的时间。

final Foo foo = createFoo();

inThread(() -> {
        foo.waitUntilUnlocked();
    });
inThread.join();
return true; //success

只有在 waitUntilUnlocked 终止后,您才能在加入后执行任何操作。

黑盒测试显示了它在您的情况下的局限性