Игнорирование вызова внутреннего статического вызова

public static ResponseBean call(Bean bean) throws Exception {
    // statements...
    IgnoreCall.ignoreMethodCall(bean);
    // statements...

    // return
}

Можно ли с помощью приведенного выше фрагмента кода протестировать метод, игнорирующий вызов IgnoreCall.ignoreMethod(Bean), без необходимости помещать весь оператор в логическое условие?

Вот фрагмент кода модульного теста:

@RunWith(PowerMockRunner.class)
@PrepareTest
public ClassHelperTest {

    @Test
    public void testCall() throws Excpetion {
        // stubbing...
        ResponseBean responseBean = ClassHelper.call(bean);
        // verify/ies
        // assert/s
    }

}

Примечания:

  • Рефакторинга ClassHelper.call(Bean) следует избегать. Даже при плохом объектно-ориентированном дизайне рефакторинг обходится дорого.
  • Сигнатура метода заблокирована, если для замены не применим другой шаблон.
  • Пробовал использовать Mockito.when и PowerMockito.when в целевом статическом методе, заглушка не работала при отладке во время выполнения.

person David B    schedule 07.12.2016    source источник
comment
Дело в том, что static — это аномалия в объектно-ориентированном дизайне; и, как вы только что заметили: ваш код гораздо сложнее тестировать. PowerMock может решить эту проблему; но я бы порекомендовал вам изменить свой производственный код. Нет статических вызовов, нет таких проблем.   -  person GhostCat    schedule 09.12.2016
comment
Если бы рефакторинг был легким делом, я бы сделал его к тому времени. К сожалению, с плохим дизайном OO я застрял на этом. Вы говорите о PowerMock can fix that problem, поделитесь как?   -  person David B    schedule 09.12.2016
comment
Ценю ваш ответ, но удаление параметров не будет для меня хорошим подходом. Случайно шаблон сборки подойдет?   -  person David B    schedule 09.12.2016
comment
Не волнуйтесь. Не работал с производственным кодом, но с фрагментом, который я сделал, сработал. Оглядываясь назад, причина, по которой это неприменимо, заключается в том, что IgnoreCall.ignoreMethodCall(Bean) имеет ряд внутренних вызовов статического метода (выходящих за рамки этого вопроса).   -  person David B    schedule 16.12.2016
comment
Я попытаюсь открыть еще один вопрос, имитирующий тот, который находится в производстве. Я дам вам пост. Извините, я обращался к SO с помощью RSS, поэтому я не получил обязательного уведомления о его присуждении, хотя награда была вычтена с моей стороны.   -  person David B    schedule 21.12.2016


Ответы (1)


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

В основном вам нужно включить IgnoreCall для статического имитации; а затем вы делаете вызовы ignoreMethodCall() бездейственными.

Но, как вы продолжаете спрашивать: основная проблема вашего вопроса заключается в том, что вы хотите имитировать метод static, который является void. У меня есть полный пример ниже, но перед этим некоторые пояснения.

Дело в том, что вы вызываете метод по двум причинам:

  1. У него есть побочный эффект
  2. Он возвращает значение и, возможно, также вызывает побочный эффект.

Метод void можно вызывать только для побочных эффектов. И дело в том, что когда вы выполняете статические насмешки, это работает на уровне класса.

Значение: вы указываете PowerMock «предотвратить» выполнение любого из статических методов некоторого класса; вы просто «стираете» побочные эффекты всех этих статических методов! Таким образом, говоря PowerMock делать эти статические макеты, все методы void уже «ушли».

Но, как уже говорилось, вы также можете вызывать методы для их возвращаемого значения. И тогда в дело вступает метод when() Mockito. Вы используете этот метод, чтобы сказать: когда этот метод, возвращающий значение, вызывается, сделайте то или иное.

Короче говоря; вот [mcve], используя элементы, которые вы просили:

package ghostcat.test;

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;

class IgnoreCall {
  public static void ignoreMethodCall(Object o) {
    System.out.println("SHOULD NOT SHOW UP: " + o);
  }
}

class CuT {
  public static Object call(Object bean) {
    System.out.println("statement1");
    IgnoreCall.ignoreMethodCall(bean);
    System.out.println("statement2");
    return "whatever";
  }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(IgnoreCall.class)
public class PMTest {
  @Test
  public void test() {
    PowerMockito.mockStatic(IgnoreCall.class);
    CuT.call("yeha");
  }
}

Как в вашем примере... есть IgnoreCall; используется внутри этого статического метода, который я только что назвал «вызовом».

Это печатает:

statement1
statement2

Когда я захожу и комментирую

//      PowerMockito.mockStatic(IgnoreCall.class);

Он печатает:

statement1
SHOULD NOT SHOW UP: yeha
statement2

Итак, простой пример, который должен показать вам точно, что вам нужно сделать.

Я работал с eclipse neon, IBM java8 JDK и просто импортировал все JAR-файлы из powermock-mockito-junit-1.6.6.zip в свой тестовый проект.

person GhostCat    schedule 09.12.2016
comment
Все еще не могу понять, почему не работают параметры-заглушки? Использовал Mockito.when и PowerMockito.when, и оба не работали соответственно. - person David B; 09.12.2016
comment
Это должен быть принятый ответ. Вы читали ссылку @GhostCat? PowerMockito.mockStatic(IgnoreCall.class); и убедитесь, что вы используете бегун PowerMocks. - person David Rawson; 15.12.2016
comment
@CyrilHorad Я тоже согласен с тем, что говорит Дэвид. Видите ли, то, что вы собираетесь сделать, задокументировано в ответе, на который я ссылаюсь. Какой части вам там не хватает? Вам действительно нужно, чтобы люди написали пример специально для вас. - person GhostCat; 15.12.2016
comment
Причина, по которой еще не принято, заключается в том, что IgnoreCall.ignoreMethodCall(Bean) имеет серию вызовов статического метода void в других классах. - person David B; 16.12.2016