【问题标题】:How to properly test this kind of timed concurrent processing service?如何正确测试这种定时并发处理服务?
【发布时间】:2015-06-05 12:56:00
【问题描述】:

我有一项服务,用于模拟 IoT 硬件组件,该组件定期将数据发送到 SOAP 端点:

private static final int DEFAULT_CHUNK_SIZE_IN_BYTES = 100 * 1024;

public void simulate(final int samplingFrequencyMs, final int uploadFrequencyMs) {
    // ...

此方法在每次samplingFrequencyMs 时间过去时生成一个 JSON 对象,并在每次uploadFrequencyMs 时间过去时调用一个 SOAP 端点,并将生成的数据分块为 DEFAULT_CHUNK_SIZE_IN_BYTES 大小的块。

例如,如果samplingFrequencyMs500 并且uploadFrequencyMs1000,那么此方法将每秒向 SOAP 端点发送 2 个生成的 JSON 字符串,如果 2 个 JSON 字符串的大小为 200 KB,则它将发送 2 个块。

还有一种方法可以停止模拟:

public void stopSimulation() {
    // ...

我已经为这个模拟器写了一个测试:

@Test
public void shouldSendProperAmountOfChunksWhenInvokingSimulate() throws InterruptedException
{
    // ...

    // when
    underTest.simulate(100, 500);
    Thread.sleep(750);

    underTest.stopSimulation();

    Thread.sleep(500);

    // then
    verify(requestServiceMock, times(EXPECTED_REQUEST_CALL_TIMES)).doRequest(uploadBinary, header);
}

但是这个测试失败了 100 次中的 1-2 次,因为服务没有被调用 EXPECTED_REQUEST_CALL_TIMES 次,所以它不稳定。当我必须验证调用方法的时间但涉及时间时,我该如何测试?我使用了750,因为它介于5001000 之间,我认为这应该可以解决问题,但我认为对于这种情况必须有一些测试最佳实践。

【问题讨论】:

  • 我假设在模拟方法中运行着生产者和消费者线程。如果消费者睡眠 1 秒,然后收集所有数据并发送到肥皂端点,而生产者在 0.5 秒内按顺序将数据插入队列中:我们可以预期消费者只会发送 1 件的条件。调用 Thread.sleep(500) 保证最少 500 毫秒的睡眠持续时间。它最终可能会等待超过 500 毫秒。
  • 有一个Timer,它每500毫秒调度一个生产者和一个消费者任务到Executor

标签: java junit testng mockito timing


【解决方案1】:

您需要做的是从 CUT 中抽象出系统时间的概念。一种典型的方法是注入一个您可以控制的Clock 对象。您的实际实现将委托给系统时钟,但在测试中您可以精确控制正在发生的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-26
    相关资源
    最近更新 更多