添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Abstract:

I have a Spring @Component that uses an autowired ExecutorService as a work pool. I'm using JUnit and Mockito to test the functionality of the component and I need to mock that Executor Service. This has been trivial for other autowired members - a generic helper, and a DAO layer for instance are easily mocked, but I need a real Executor Service.

Code:

@RunWith(MockitoJUnitRunner.class)
public class MadeUpClassNameTest{
  @Mock
  private ExecutorService executor;
  @Before
  public void initExecutor() throws Exception{
      executor = Executors.newFixedThreadPool(2);
  @InjectMocks
  private ASDF componentBeingAutowired;

This alone doesn't work, the results of invokeAll() is always an empty list.

Attempting to more explicitly mock the executor method also doesn't work...

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

I get the cryptically worded exception:

You cannot use argument matchers outside of verification or stubbing.

(I thought this was a stubbing ?)

I could provide a thenReturn(Answer<>) method, but I'd like to make sure that the code actually works with an executor, a fair bit of the code is devoted to mapping the results of Futures.

Problem How do I provide a real (or functionally usable mock) Executor Service ? Alternatively, is my difficulty in testing this component a sign that this is a poor design in need of refactoring, or possibly a bad test scenario ?

Notes I want to stress that my problem is NOT getting Mockito or Junit set up. Other mocks and tests work correctly. My problem is specific only to the particular mock above.

Using: Junit 4.12, Mockito 1.10.19, Hamcrest 1.3

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

This causes your local copy of executor to be set, but not the one that is injected.

I would recommend using constructor injection in on your componentBeingAutowired and create a new one in your unit test and exclude Spring dependencies. Your test could then look like something below:

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

Another way is to use ReflectionTestUtils to inject the executor

@Before
public void initExecutor() {
  ReflectionTestUtils.setField(componentBeingAutowired, "executor", Executors.newFixedThreadPool(2);
                In such case I'm getting 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
– Andrei_N
                Mar 16, 2017 at 13:01
public class MadeUpClassNameTest{
private final ExecutorService executor = Executors.newFixedThreadPool(2);
@Test
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.