【问题标题】:Mock an Autowired ExecutorService模拟 Autowired ExecutorService
【发布时间】:2015-12-04 20:47:56
【问题描述】:

摘要:

我有一个 Spring @Component,它使用自动装配的 ExecutorService 作为工作池。我正在使用 JUnit 和 Mockito 来测试组件的功能,我需要模拟那个 Executor Service。这对于其他自动装配的成员来说是微不足道的 - 一个通用帮助器,例如一个 DAO 层很容易模拟,但我需要一个 真正的 Executor Service。

代码:

@RunWith(MockitoJUnitRunner.class)
public class MadeUpClassNameTest{

  @Mock
  private ExecutorService executor;

  @Before
  public void initExecutor() throws Exception{
      executor = Executors.newFixedThreadPool(2);
  }

  @InjectMocks
  private ASDF componentBeingAutowired;
...

仅此一项不起作用,invokeAll() 的结果始终是一个空列表。

尝试更明确地模拟 executor 方法也不起作用...

@Test
public void myTestMethod(){
    when(executor.invokeAll(anyCollection()))
        .thenCallRealMethod();
    ...
}

我得到了一个措辞含糊的异常:

您不能在验证或存根之外使用参数匹配器。

(我以为这是一个存根?)

可以提供一个thenReturn(Answer<>) 方法,但我想确保代码实际上与执行器一起工作,相当一部分代码专门用于映射Futures 的结果.

问题 如何提供真实(或功能可用的模拟)执行器服务?或者,我在测试这个组件时遇到的困难是否表明这是一个需要重构的糟糕设计,或者可能是一个糟糕的测试场景?

注意事项 我想强调我的问题是没有设置 Mockito 或 Junit。其他模拟和测试工作正常。我的问题只针对上面的特定模拟。

使用:Junit 4.12、Mockito 1.10.19、Hamcrest 1.3

【问题讨论】:

    标签: spring unit-testing mockito executorservice


    【解决方案1】:

    我认为注入 Mock 后会运行以下代码。

    @Before
    public void initExecutor() throws Exception{
      executor = Executors.newFixedThreadPool(2);
    }
    

    这会设置您的 executor 的本地副本,但不会设置注入的副本。

    我建议在您的componentBeingAutowired 上使用constructor injection,并在您的单元测试中创建一个新的并排除Spring 依赖项。您的测试可能如下所示:

    public class MadeUpClassNameTest {
        private ExecutorService executor;
    
        @Before
        public void initExecutor() throws Exception {
            executor = Executors.newFixedThreadPool(2);
        }
    
        @Test
        public void test() {
            ASDF componentBeingTested = new ASDF(executor);
            ... do tests
        }
    }
    

    【讨论】:

      【解决方案2】:

      另一种方法是使用ReflectionTestUtils注入执行器

      @Before
      public void initExecutor() {
        ReflectionTestUtils.setField(componentBeingAutowired, "executor", Executors.newFixedThreadPool(2);
      }
      

      【讨论】:

        【解决方案3】:

        你可以使用@Spy注解。

        @RunWith(MockitoJUnitRunner.class)
        public class MadeUpClassNameTest{
        
            @Spy
            private final ExecutorService executor = Executors.newFixedThreadPool(2);
        
            ....
        
        }
        

        【讨论】:

        • 在这种情况下,我会收到org.mockito.exceptions.base.MockitoException: Unable to initialize @Spy annotated field 'someField'. Mockito cannot mock this class: class java.util.concurrent.Executors$FinalizableDelegatedExecutorService. Mockito can only mock non-private & non-final classes. If you're not sure why you're getting this error, please report to the mailing list. Underlying exception : java.lang.IllegalStateException: Error invoking java.lang.ClassLoader#findClass
        【解决方案4】:

        你可以使用@Spy注解。

        @RunWith(MockitoJUnitRunner.class)
        public class MadeUpClassNameTest{
        @Spy
        private final ExecutorService executor = Executors.newFixedThreadPool(2);
        
        @Test
        ...
        }
        

        【讨论】:

          猜你喜欢
          • 2017-12-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-07-06
          相关资源
          最近更新 更多