【问题标题】:How to unit test that ExecutorService spawns new thread for task?如何对 ExecutorService 为任务生成新线程进行单元测试?
【发布时间】:2010-12-12 18:30:18
【问题描述】:

如何在使用 ExecutorService 时单元测试是否为 Runnable 任务生成了一个新线程?

基本上,我的应用程序有一个静态线程池。

public static final ExecutorService executorService = Executors.newCachedThreadPool();

我想将这个线程池用于我的单元测试,而不是模拟一个或注入一个新的线程池,因为不同的线程池可以显着改变我的应用程序的行为(固定、缓存和计划, 等等);我想确保使用它的运行时线程池测试应用程序的行为。

缓存线程池似乎最适合我。问题在于,由于它是静态的,并且线程被缓存了 60 秒,因此只有第一个测试实际上会在池中生成一个新线程,而后续测试会重用该线程。

单元测试代码:

public void testDoCallExecutesTaskInAnotherThread() {    
    final Client client = this.createClient();
    final ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) client.getExecutorService(); // gets the static thread pool
    final int initPoolSize = threadPoolExecutor.getPoolSize();
    final Response response = client.doCall();
    Assert.assertEquals(initPoolSize + 1, threadPoolExecutor.getPoolSize());
}

我们将不胜感激有关如何使这项工作发挥作用的建议,或完全采用其他方法。

【问题讨论】:

  • 您为什么要关心客户端是否在单独的线程中执行调用?我可以看到关心诸如“这需要多长时间?”之类的事情。或“此操作是否正确响应中断。”但就目前而言,这似乎是一个糟糕的单元测试应用程序。
  • 好问题。此特定客户端必须异步执行 Web 服务调用,以便它不会阻止使用它的对象——这是我的应用程序中的性能问题。我不是在等待响应,我只是想确保进行 Web 服务调用的任务是异步生成的。
  • 我就是这么想的。所以你真正应该测试的是它是否“持有使用它的对象”。也就是说,需要多长时间?我可以用这样的方式实现 doCall,它需要两天时间才能返回,但仍然会导致执行程序创建另一个线程;即使违反了您的标准,您的单元测试仍然会通过。

标签: java multithreading concurrency


【解决方案1】:

模拟ThreadFactory

  ThreadFactory mock = new CustomObservableThreadFactory();
  ExecutorService executorService = Executors.newCachedThreadPool(mock);
  1. 像往常一样将 ExecutorService 注入到被测类中
  2. 但是使用 自定义 ThreadFactory 来创建缓存的 ThreadPool: 每当要调用新线程时,都会调用 ThreadFactory。 然后,您可以根据需要跟踪这些实例化,例如使用侦听器或计数器。

【讨论】:

  • 您介意“像往常一样”展示您是如何做到的,还是提供参考?
猜你喜欢
  • 2014-02-14
  • 2012-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-21
  • 2013-11-26
  • 2015-07-08
  • 1970-01-01
相关资源
最近更新 更多