TDD:测试等待功能

时间:2016-08-10 07:07:45

标签: java multithreading unit-testing asynchronous tdd

我有一个类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毫秒。“

您是否对可靠的快速测试有更好的想法,而不是针对竞争条件开放?

1 个答案:

答案 0 :(得分:1)

这个想法是编写一个测试,如果你的锁是假的,它最终会失败,但是在同步方面没有一个快速可靠的黑盒测试。

想象一下,其他人,一位自由撰稿人,正在撰写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终止后才会在加入后执行任何操作。

黑盒测试显示其在您情况下的限制