Статьи

Иногда TDD требует молот

Несмотря на то, что для платформы Java доступно множество библиотек макетов, лишь немногие из этих изящных платформ способны насмехаться над модификаторами static и final не поддерживающими mock-friendly. Статические (или классовые) методы, хотя и удобны для фабрик, становятся неприятностью для фреймворка, такого как Mockito , однако, с включением PowerMock , вы получаете себе пресловутый молот. hammerj

Как я уже писал ранее , мне приходилось иметь дело со сторонней библиотекой, которая используется для интеграции с сетевым сервисом. Эта библиотека, по сути, жестко связана с homebase, что, естественно, создает некоторые проблемы при попытке протестировать код, основанный на этой библиотеке. Кроме того, указанная библиотека содержала static метод для создания экземпляров специализированного класса, от которого, естественно, зависел мой код.

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

Для начала вам нужно использовать две аннотации на уровне класса — @RunWith для указания класса PowerMockRunner (это аннотация JUnit) и другую @PrepareForTest , которая принимает класс со static методами, которые вы хотите смоделировать. @PrepareForTest предоставляется PowerMock.

В моем случае класс, содержащий static метод, называется QTP ; мой тестовый класс выглядит так:

1
2
3
4
5
6
@RunWith(PowerMockRunner.class)
@PrepareForTest(QTP.class)
public class CreateCommandTest {
  @Test
  public void testCreateRequest() throws Exception {}
}

Далее, в вашем тестовом методе вы используете PowerMokito mockStatic , который принимает класс (снова) со статическими методами, которые вы хотите смоделировать.

1
2
3
4
5
@Test
public void testCreateRequest() throws Exception {
  PowerMockito.mockStatic(QTP.class);
  //....
}

Затем вы можете mockStatic статический метод для класса, который вы передаете, в mockStatic и аннотацию @PrepareForTest как вы обычно делаете с Mockito. Например, я могу использовать метод when чтобы указать, что я хочу получить, когда вызывается этот статический метод.

01
02
03
04
05
06
07
08
09
10
@Test
public void testCreateRequest() throws Exception {
  PowerMockito.mockStatic(QTP.class);
  QTP qtpThing = mock(QTP.class); //normal Mockito mocking
  //QTP.create is static
  when(QTP.create("dm2q", "0C4F7501UDC8C1EB43B06C988")).thenReturn(qtpThing);
  //QTP.createRecord isn't static
  when(qtpThing.createRecord(any(Tckt.class))).thenReturn(new Long(1000000L));
  //...
}

Наконец, вы можете использовать PowerMock, чтобы убедиться, что ваш смоделированный статический метод действительно вызван. Требования здесь немного прикольные; то есть требуется сначала указать, сколько раз одной строкой кода, а затем фактически вызвать статический метод .

1
2
3
4
5
6
7
@Test
public void testCreateRequest() throws Exception {
  //...
  PowerMockito.verifyStatic(Mockito.times(1));
  QTP.create("dm2q", "0C4F7501UDC8C1EB43B06C988");
  //...
}

Да, это немного сбивает с толку, я знаю.

Тем не менее, как многие люди в мире Java давно поняли, статические методы несколько сложны, когда дело доходит до тестирования . То есть, хотя метод, который концептуально не имеет состояния, на первый взгляд кажется достаточно простым для тестирования, проблемы возникают, когда этот статический метод выполняет что-то вроде попадания в базу данных или, в моем случае, вызывает веб-сервис для сетевого актива. Нет простого способа переопределить такое поведение (если, конечно, вы не вытащите молоток).

Статические методы имеют место. Но когда дело доходит до тестирования кода, будь то устаревшая или какая-либо сторонняя библиотека, модификатор static требует молотка, и, как я надеюсь, я вам показал, PowerMock — это тот молоток.

Справка: иногда TDD требуется молоток от нашего партнера по JCG Эндрю Гловера в блоге The Disco Blog .