Mockito просит добавить @PrepareForTest для класса даже после добавления @PrepareForTest

У меня есть следующий простой код. У меня есть класс (TestClass), и я хочу проверить "someMethod". Существует внешний статический метод, который вызывается моим "someMethod". Я хочу, чтобы Powermock статический метод возвращал мне какой-то фиктивный объект. У меня есть @PrepareForTest (ExternalClass.class) в начале, но когда я его выполняю, он дает ошибку:

Класс ExternalClass не подготовлен к тестированию. Чтобы подготовить этот класс, добавьте класс в аннотацию '@PrepareForTest'. Если вы не используете эту аннотацию, добавьте аннотацию на уровне класса или метода.

Пожалуйста, помогите мне указать, что не так, как я использовал @PrepareForTest

@RunWith(PowerMockRunner.class)
@PrepareForTest(ExternalClass.class)
public class xyzTest {  
    @Mock
    private RestTemplate restTemplate;

    @Mock
    private TestClass testClass;

    @BeforeClass
    private void setUpBeforeClass() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testSuccessCase() {
        Boolean mockResponse = true;
        ResponseEntity<Boolean> response = new ResponseEntity<Boolean>(mockResponse, HttpStatus.OK);
        SomeClass someClass = new SomeClass("test", "1.0.0", "someUrl", "someMetaData");

        PowerMockito.mockStatic(ExternalClass.class);

        Mockito.when(restTemplate.postForEntity(any(String.class), any(String.class), eq(Boolean.class))).thenReturn(response);
        Mockito.when(ExternalClass.getSomeClass(any(String.class))).thenReturn(someClass);

        Boolean result = testClass.someMethod("test");

        Assert.isTrue(result);
        Mockito.verify(restTemplate, times(1)).postForObject(any(String.class), any(String.class), any());
    }
}

Ответ 1

Убедитесь, что вы добавили @RunWith(PowerMockRunner.class) в начало вашего класса.

:: редактировать :: два года спустя...

Никогда не используйте PowerMockito, вам не нужно.

Если вам это нужно, вы, скорее всего, нарушили принципы SOLID, и ваш дизайн ошибочен.

Вместо этого исправьте свой дизайн.

Ответ 2

Как и в последнем ответе, моя проблема заключалась также в смешивании тестовой аннотации из TestNG вместо теста Junit.

import org.junit.Test; // works

import org.testng.annotations.Test // did not work

Очень абсурдная ошибка, и я потратил более 5 часов на отладку: (

Ответ 3

У меня была такая же ошибка, разрешив это, добавив

@Rule
public PowerMockRule rule = new PowerMockRule();

внутри тестового класса.

Ответ 4

Для тех, кто пытается заставить это работать с Junit 5, если вы используете powermock-module-junit4 которая заявляет о совместимости с 4+, библиотека все равно не распознает:

import org.junit.jupiter.api.Test;

и это бросит:

org.powermock.api.mockito.ClassNotPreparedException

когда @PrepareForTest применяется к классу, который вы хотите использовать для статического макета. Если вы хотите использовать PowerMock, вам придется вернуться к Junit 4 или создать MockWrapper для вашего статического метода.

PowerMock 2.0: дорожная карта Github

Ответ 5

У меня была такая же ошибка, но она была решена. Моя проблема заключалась в том, что я включил powermock-module-junit4, но включил мою тестовую аннотацию из TestNG вместо Junit.

Ответ 6

Если приведенные выше ответы не работают, попробуйте extends PowerMockTestCase. Этот трюк сработал для меня.

Пример: public class xyzTest extends PowerMockTestCase

Ответ 7

У меня была такая же ошибка. Я использовал TestNG для запуска тестов. Мне пришлось использовать следующий метод, чтобы исправить вышеуказанную проблему.

@ObjectFactory
    public IObjectFactory getObjectFactory() {
        return new PowerMockObjectFactory();
    }

Ответ 8

Хотя самый лучший ответ здесь, без сомнения, правильный, он не отвечает на вопрос, зачем это нужно; или, например, почему то же самое не будет работать с добавлением @RunWith(MockitoJUnitRunner.class).

Дело в том, что PowerMockRunner использует API инструментария PowerMockRunner, через библиотеку javassist, это позволяет изменять классы, например удалять final или mock static (некомпилируемые постоянные времени).

В процессе изменения (инструментирования) определенного класса они добавляют интерфейс к нему, называемый PowerMockModified. Это интерфейс маркера, который обозначает, что имелись определенные инструменты байт-кода. Позже в коде они просто проверяют, был ли класс, который вы используете в @PrepareForTest самом деле каким-то образом инструментирован или нет, с помощью такого метода:

    private boolean isModifiedByPowerMock() {
        return PowerMockModified.class.isAssignableFrom(this.type);
    }

Оказывается, что PowerMockRunner делает некоторые инструменты, в то время как MockitoJUnitRunner не делает; Таким образом, ошибка, которую вы получаете.