Lock.tryLock超时异常的JUnit测试场景

时间:2014-06-01 10:46:48

标签: java multithreading concurrency junit timeout

我想测试以串行方式执行任务并抛出的服务 TimeOutInServiceException如果某项任务等待超过5秒。我想测试超时场景。

我写的完整测试场景非常复杂,我正在寻找最简单的解决方案。

测试此类服务的关键点是

  • 服务超时异常(不是通过返回一些特殊值)
  • 我们必须在单独的线程中启动更长的阻塞任务
  • 我们无法通过异常@Test(expected = ...)退出测试,因为在其他测试期间,后台阻止服务中较长的任务线程仍然存在

所以,我目前的测试用例看起来像这样:

  1. 创建Executor
  2. 制作持久Callable / Runnable
  3. 创建失败(必须超时)Callable / Runnable
  4. .submit()执行任务的长任务
  5. 睡一段时间,以确保首先开始更长的任务
  6. .submit()失败超时任务
  7. .shutdown()执行者和.awaitTermination()
  8. .get().assertTrue()第一项任务已完成确定
  9. ExecutionException抓取.get()关于失败任务和存储原因的准备参考:

    Exception thrown = null;
    try {
       timeoutedTaskFuture.get();
    } catch ( ExecutionException ex ) {
       thrown = (Exception)ex.getCause();
    } 
    
  10. 检查预期的例外情况:

    assertTrue( thrown instanceof TimeOutInServiceException );
    
  11. 有没有更好的方法来测试这样的场景?

1 个答案:

答案 0 :(得分:0)

如果您的代码严重依赖于Lock功能,那么我会考虑引入某种构造来为您的代码提供Lock实例。然后,您可以用您的提供者/供应商替换构造以返回模拟的Lock实例。这将允许您测试特定条件,而无需创建精细的单元测试。

使用Google Guava你可以用JMock做这样的事情:

// this class supplies real Lock instances.
public class LockSupplier implements Supplier<Lock> {

    @Override
    public Lock get() {
        return new ReentrantLock();
    }

}

// this class supplies your mocked instances for your unit test.
public class MockLockSupplier implements Supplier<Lock> {

    private Lock mockedLock;

    public MockLockSupplier(Mockery context) {
        mockedLock = context.mock(Lock.class);
    }

    @Override
    public Lock get() {
        return mockedLock;
    }

}

在您的测试用例中设置锁定供应商之后,只需在JMock设置您的期望。