Как издеваться над частным методом тестирования с помощью PowerMock?


У меня есть класс, который я хотел бы проверить с помощью публичного метода, который вызывает private one. Я хотел бы предположить, что частный метод работает правильно. Например, я хотел бы что-то вроде doReturn....when.... Я обнаружил, что есть возможное решение с помощью PowerMock, но это решение не работает для меня. Как это можно сделать? У кого-нибудь была эта проблема?

4 55

4 ответа:

Я не вижу здесь проблемы. С помощью следующего кода, используя API Mockito, мне удалось сделать именно это:

public class CodeWithPrivateMethod {

    public void meaningfulPublicApi() {
        if (doTheGamble("Whatever", 1 << 3)) {
            throw new RuntimeException("boom");
        }
    }

    private boolean doTheGamble(String whatever, int binary) {
        Random random = new Random(System.nanoTime());
        boolean gamble = random.nextBoolean();
        return gamble;
    }
}

и вот тест JUnit :

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.powermock.api.support.membermodification.MemberMatcher.method;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class CodeWithPrivateMethodTest {

    @Test(expected = RuntimeException.class)
    public void when_gambling_is_true_then_always_explode() throws Exception {
        CodeWithPrivateMethod spy = PowerMockito.spy(new CodeWithPrivateMethod());

        when(spy, method(CodeWithPrivateMethod.class, "doTheGamble", String.class, int.class))
                .withArguments(anyString(), anyInt())
                .thenReturn(true);

        spy.meaningfulPublicApi();
    }
}

универсальное решение, которое будет работать с любой системой тестирования (Если ваш класс неfinal), чтобы вручную создать свой собственный макет.

  1. измените свой частный метод на защищенный.
  2. в вашем тестовом классе расширьте класс
  3. переопределите ранее закрытый метод, чтобы вернуть любую константу, которую вы хотите

Это не использует никаких рамок, так что его не так элегантно, но он всегда будет работать: даже без PowerMock. Кроме того, вы можете использовать Mockito, чтобы сделать шаги #2 & #3 для вас, если вы уже сделали шаг #1.

чтобы издеваться над частным методом напрямую, вам нужно будет использовать PowerMock, как показано в другого ответа.

Я знаю способ ny, который вы можете назвать частной функцией для тестирования в mockito

@Test
    public  void  commandEndHandlerTest() throws  Exception
    {
        Method retryClientDetail_privateMethod =yourclass.class.getDeclaredMethod("Your_function_name",null);
        retryClientDetail_privateMethod.setAccessible(true);
        retryClientDetail_privateMethod.invoke(yourclass.class, null);
    }

по какой-то причине ответ Брайса не работает для меня. Я смог немного манипулировать им, чтобы заставить его работать. Это может быть просто потому, что у меня более новая версия PowerMock. Я использую 1.6.5.

import java.util.Random;

public class CodeWithPrivateMethod {

    public void meaningfulPublicApi() {
        if (doTheGamble("Whatever", 1 << 3)) {
            throw new RuntimeException("boom");
        }
    }

    private boolean doTheGamble(String whatever, int binary) {
        Random random = new Random(System.nanoTime());
        boolean gamble = random.nextBoolean();
        return gamble;
    }
}

тестовый класс выглядит следующим образом:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.doReturn;

@RunWith(PowerMockRunner.class)
@PrepareForTest(CodeWithPrivateMethod.class)
public class CodeWithPrivateMethodTest {
    private CodeWithPrivateMethod classToTest;

    @Test(expected = RuntimeException.class)
    public void when_gambling_is_true_then_always_explode() throws Exception {
        classToTest = PowerMockito.spy(classToTest);

        doReturn(true).when(classToTest, "doTheGamble", anyString(), anyInt());

        classToTest.meaningfulPublicApi();
    }
}