Unable to get mocked instance of Executor in separate class
Asked Answered
B

1

5

I am trying to mock ExecutorService and Executors from java.util.concurrent package.

I am able to get the mocked object if I try to get the object within the same class (test class) where I am mocking the object. However if I try to get the mocked object in a different class (the class I want to test) then it returns actual object from java.util.concurrent. Following is the code snippet.

The class I want to test:

public class MyClass
{
    public void myMethod()
    {
        ExecutorService executorService = Executors.newFixedThreadPool(2, new MyThreadFactory());

        for (int count = 0; count < 2; count++)
        {
            executorService.submit(new Thread());
        }
    }
}

class MyThreadFactory implements ThreadFactory
{
    @Override
    public Thread newThread(Runnable r)
    {
        return null;
    }
}    

My Test class looks like:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Executors.class)
public class MyClassTest
{
    @Test
    public void testMyMethod()
    {
        prepareMocks();            

        //Code to get mocked object (See testMethod below)
    }

    private void prepareMocks()
    {
        ExecutorService executorService = PowerMock.createMock(ExecutorService.class);
        EasyMock.expect(executorService.submit(EasyMock.anyObject(Runnable.class))).andReturn(null).anyTimes();

        PowerMock.mockStatic(Executors.class);
        EasyMock.expect(Executors.newFixedThreadPool(EasyMock.anyInt(), EasyMock.anyObject(ThreadFactory.class))).andReturn(executorService).anyTimes();

        PowerMock.replay(executorService, Executors.class);
    }
}

If MyClassTest.testMyMethod() is as below, it returns mocked oject.

    @Test
    public void testMyMethod()
    {
        prepareMocks();

        //Following code reurned mocked instance of ExecutorService
        ExecutorService executorService = Executors.newFixedThreadPool(2, new MyThreadFactory());

        for (int count = 0; count < 2; count++)
        {
            executorService.submit(new Thread());
        }
    }

However if I change the test method to call myClass.myMethod() it returns actual instance instead of mocked instance in myMethod().

@Test
public void testMyMethod()
{
    prepareMocks();

    /*
     * Within myClass.myMethod(), Executors.newFixedThreadPool() returns actual instance of ThreadPoolExecutor
     * instead of mocked object
     */
    MyClass myClass = new MyClass();
    myClass.myMethod();
}

I am expecting to get a mocked instance of Executors/ExecutorService in myClass.myMethod.

Is this the expected behavior? Could anyone explain the behavior? Am I missing anything?

Border answered 18/12, 2013 at 13:48 Comment(0)
L
7

You need to let the class know that there is going to be a Mock incoming. In your @PrepareForTest(), try also including the class that is calling the static. This way you are telling it to mock the execution of the static, as well as telling it where this mock is going to be taking place. Try updating the @PrepareForTest({Executors.class, MyClass.class}).

When you have it so your test class is calling the static directly, you have the Executors.class in the @PrepareForTest() so it will know to "inject" that mock into the execution. When you call your other class, at runtime the class you are calling it doesn't know to use the mock version of your static class, which is why it is resorting to the original code that it knows about, not the mock outside its scope. Adding the class that CALLS the static object (the one you test), will allow the static mock you have to be hooked in when it is ran.

Lindberg answered 18/12, 2013 at 15:16 Comment(1)
Do you know why it isn't always necessary? For example when mocking Session. Please consider following: ideone.com/LIl0H7 (testing class) and ideone.com/aPuEoL (external class).Papillote

© 2022 - 2024 — McMap. All rights reserved.