Невозможно получить смоделированный экземпляр Executor в отдельном классе

Я пытаюсь издеваться над ExecutorService и Executors из пакета java.util.concurrent.

Я могу получить макет объекта, если я пытаюсь получить объект в том же классе (тестовый класс), где я насмехаюсь над объектом. Однако, если я пытаюсь получить макет объекта в другом классе (класс, который я хочу проверить), он возвращает фактический объект из java.util.concurrent. Ниже приведен фрагмент кода.

Класс, который я хочу проверить:

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;
    }
}    

Мой тестовый класс выглядит так:

@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);
    }
}

Если MyClassTest.testMyMethod() как показано ниже, он возвращает ложный объект.

    @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());
        }
    }

Однако, если я изменю тестовый метод на вызов myClass.myMethod(), он возвращает фактический экземпляр вместо смоделированного экземпляра в 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();
}

Я ожидаю получить поддельный экземпляр Executors/ExecutorService в myClass.myMethod.

Это ожидаемое поведение? Может ли кто-нибудь объяснить поведение? Я что-то пропустил?

1 ответ

Решение

Вы должны сообщить классу, что будет Mock входящий. В вашем @PrepareForTest()попробуйте также включить класс, который вызывает статический. Таким образом, вы говорите ему высмеивать выполнение статики, а также сообщаете ему, где будет происходить это издевательство. Попробуйте обновить @PrepareForTest({Executors.class, MyClass.class}),

Если у вас есть такой тестовый класс, который вызывает статический напрямую, у вас есть Executors.class в @PrepareForTest() так что он будет знать, чтобы "вставить" этот макет в выполнение. Когда вы вызываете ваш другой класс, во время выполнения класс, который вы вызываете, не знает, использовать ли имитационную версию вашего статического класса, поэтому он прибегает к исходному коду, о котором он знает, а не к макету вне его области видимости., Добавление класса, который ВЫЗЫВАЕТ статический объект (тот, который вы тестируете), позволит использовать статический макет, который вы должны подключить при запуске.

Другие вопросы по тегам