【问题标题】:Replacing ManagedExecutorService with ExecutorService in test在测试中用 ExecutorService 替换 ManagedExecutorService
【发布时间】:2016-10-09 21:27:24
【问题描述】:

我有一些使用 Java EE ManagedExecutorService 的服务(在 Wildfly 9 中)

public class FooService{
    @Resource
    ManagedExecutorService executorService;
}

对于 Mockito 的测试,我想使用“正常”ExecutorService

@RunWith(MockitoJUnitRunner.class)
public class FooServiceTest{
   @Spy
   ManagedExecutorService executorService = Executors.newFixedThreadPool(5);
}

这段代码显然无法编译,因为ExecutorService 不是ManagedExecutorService

在服务中使用ExecutorService 时,测试运行没有错误,但Wildfly 无法注入服务。

public class FooService{
    @Resource
    ExecutorService executorService;
}

@RunWith(MockitoJUnitRunner.class)
public class FooServiceTest {
   @Spy
   ExecutorService executorService = Executors.newFixedThreadPool(5);
}

可以通过委托给ExecutorService来创建ManagedExecutorService

@Spy
ManagedExecutorService executorService = new ManagedExecutorService() {

   ExecutorService executorService = Executors.newFixedThreadPool(5);
   @Override
   public void shutdown() {
       executorService.shutdown();
   }

   // delegate for all (12) methods
}

有没有更简单的方法在测试中使用 ExecutorService 而无需更改在 Wildfly 中运行的服务?

【问题讨论】:

  • 为什么需要ManagedExecutorService 的非模拟实例?这是一个很容易被模拟的界面。
  • @SpaceTrucker:嗯,它不是单元测试,所以提交给 ExecutorService 的任务应该实际运行。可以使用 Arquillian,但我认为只使用 Java SE ExecutorService 可能更简单。
  • 那为什么不使用一个模拟来运行提交的任务呢?只需相应地执行 Answer site.mockito.org/mockito/docs/current/org/mockito/stubbing/…
  • @SpaceTrucker:这对于简单的 Runnables 来说是可能的,但如果服务使用通过提交返回的 Future,它会变得复杂,不是吗?
  • 我认为您需要重新考虑测试的范围。如果范围是在ManagedExecutorService 提供的环境中实际运行任务,那么您实际上需要提供它并使用干净启动的容器进行此测试。

标签: java jakarta-ee concurrency mockito wildfly


【解决方案1】:

我使用注入模式:

class DefaultImpl {
 static DefaultFactory me;
 static DefaultFactory getCurrentInstance()
  { if (me == null) {
     me = new DefaultFactory();
    }
    return me;
  }
void setCurrentInstance(DefaultFactory df){
  me = df;
}
 ExecutorService getExecutorService(){
   // lookup and return ManagedExecutorService
 }
}
class TestImpl extends DefaultImpl{
  TestImpl(){
    DefaultFactory.setCurrentInstance(this); <-- this now sets your TestImpl for any call
  }
  ExecutorService getExecutorService(){
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    return executorService;
  }
}

//junit
@Test
void someTest(){
 new TestImpl();
 // do something all your calls will use non managed executor service
}

您也可以从 junit setup() 调用 new TestImpl()。此外,如果您想让它更灵活,那么您可以拥有一个 BaseImpl 并让 DefaultImpl 和 TestImpl 扩展它。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-28
    • 1970-01-01
    相关资源
    最近更新 更多