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

#java #unit-testing #mocking #powermock

#java #модульное тестирование #издевательство #powermock

Вопрос:

У меня есть очень-очень простой класс, который имеет частный метод. Вопрос в том, как подавить вызов этого метода?

Вот мой код:

 public class Example { 
    private int value;

    public Example(int value) {
        this.value = value;
        method();
    }

    private void method() {
        throw new RuntimeException();
    }

    public int getValue() {
        return value;
    }
}
  

И код теста (по крайней мере, попытка):

 public void test() throws Exception {

    PowerMockito.doNothing().when(Example.class, "method");
    final int EXPECTED_VALUE = 1;
    Example example = new Example(EXPECTED_VALUE);
    int RETRIEVED_VALUE = example.getValue();

    assertEquals(RETRIEVED_VALUE, EXPECTED_VALUE);
    verifyPrivate(Example.class, times(1)).invoke("method");
}
  

UPD

Для меня важно соблюдать эти два условия:

  1. PowerMockito.doNothing().when(Example.class, "method");
  2. PowerMockito.verifyPrivate(Example.class, times(1)).invoke("method");

Комментарии:

1. С какой стати вам просто создавать новое исключение? Я не понимаю.

2. //method(); должно сработать

3. Это всего лишь пример реального класса.

4. @Aaron Что тебе разрешено и чего не разрешено делать?

5. Хорошо, я думаю, он спрашивает, как издеваться method , чтобы его фактическая реализация не вызывалась. Это «как мне написать этот модульный тест?» вопрос.

Ответ №1:

Поскольку вы не можете модифицировать тестируемый код. Я думаю, что нет идеального решения. Вам нужно частично смоделировать Example экземпляр.

 List list = new LinkedList();
List spy = spy(list);
//You have to use doReturn() for stubbing
doReturn("foo").when(spy).get(0);
  

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


Итак, я предлагаю следующий обходной путь, состоящий из двух тестов. Первый тест удаляет private method из класса, создает экземпляр Example и проверяет, что Example правильно инициализирован. Второй тест создает экземпляр Example и проверяет, что RuntimeException (частный method побочный эффект).

 import static org.junit.Assert.assertEquals;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
import static org.powermock.api.support.membermodification.MemberModifier.suppress;

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;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Example.class)
public class ExampleTest {
    @Test
    public void constructor_should_initialize_the_v2alue() throws Exception {
        suppress(method(Example.class, "method"));

        final int EXPECTED_VALUE = 1;
        Example example = PowerMockito.spy(new Example(EXPECTED_VALUE));
        int RETRIEVED_VALUE = example.getValue();

        assertEquals(RETRIEVED_VALUE, EXPECTED_VALUE);
    }

    @Test(expected=RuntimeException.class)
    public void constructor_should_invoke_the_private_method() throws Exception {
        new Example(1);
    }
}
  

Комментарии:

1. На самом деле мне нужно убедиться, что этот метод также был вызван (без вызова).

2. ИМХО, это невозможно с powermock / mockito. Может быть, вы можете посмотреть на runtime weaving / aop с aspectj