Дразнить сервис, который выдает исключение? - PullRequest
2 голосов
/ 23 февраля 2012

Я хочу протестировать метод BackSean-компонента JSF "isInProgress", который делегирует методу службы "isInProgress".Когда сервисный метод выдает исключение, бин должен поместить событие в определенный регистратор событий и вернуть false.

Когда я отлаживаю следующий тест, я попадаю в блок catch.Смежный сервис не генерирует исключение, но возвращает «ответ по умолчанию», который является ложным для этого логического значения. Что я делаю не так?

Мне также интересно, можно ли каким-то образом избежать попытки "ловить" вызов "когда", так как действительное исключение поглощается тестируемым компонентом.На самом деле, я думаю, что «декларативно» передачи имени метода «когда» должно быть достаточно. Есть ли способ получить этот очиститель?

@Test
public void testIsInProgressExeption() {
    //prepare object and inputs
    MyBean bean = new MyBean();
    MyService service = mock(MyAdapterService.class);
    bean.setService(service);

    try {
        when(bean.getService().isInProgress()).thenThrow(new Exception());
    } catch (Exception e) {

        //prepare expected object and result
        MyBean expectedBean = new MyBean();
        expectedBean.setService(service);
        boolean expected = false;

        //execute method under test
        boolean actual = bean.isInProgress();

        //check return values and exceptions
        assertEquals(expected, actual);

        //check that bean did not change unexpectedly
        assertTrue(bean.equals(expectedBean));

        //check sideeffects on event log
        assertTrue(logEvents.containsMessage("MDI09"));
    }

}

Для справки приведен обновленный тест:

@Test
public void testIsInProgressExeption() throws Exception {
    //prepare object and inputs
    MyBean bean = new MyBean();
    MyService service = mock(MyAdapterService.class);
    bean.setService(service);

    when(bean.getService().isInProgress()).thenThrow(new Exception());

    //prepare expected object and result
    MyBean expectedBean = new MyBean();
    expectedBean.setService(service);
    boolean expected = false;

    //execute method under test
    boolean actual = bean.isInProgress();

    //check return values and exceptions
    assertEquals(expected, actual);

    //check that bean did not change unexpectedly
    assertTrue(bean.equals(expectedBean));

    //check sideeffects on event log
    assertTrue(logEvents.containsMessage("MDI09"));

}

Ответы [ 3 ]

3 голосов
/ 23 февраля 2012

Переместите предложение when из блока try и измените его на:

when(service.isInProgress()).thenThrow(new Exception());

Теперь оно должно вызывать исключение при вызове.

0 голосов
/ 28 февраля 2012

Для записей я проводил тестирование на основе состояния. Интересно, что Фаулер опубликовал в http://martinfowler.com/articles/mocksArentStubs.html очень хорошую статью, которая идет по тому же пути, но затем отличает ее от насмешек и тестирования на основе взаимодействия.

0 голосов
/ 23 февраля 2012

Вы делаете это неправильно. Сначала вы должны выложить свой тест с ключевыми словами BDD или AAA , с BDD:

@Test public void testIsInProgressExeption() {
    // given

    // when

    // then

}

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

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

when(bean.getService().isInProgress()).thenThrow(new Exception());

Однако вместо bean.getService() следует указывать непосредственно ссылку на сервис, это неудобно.

Я не совсем понимаю, почему вы создаете новый экземпляр компонента в предложении catch, это странно. Но вот как я буду писать тест. Обратите внимание на то, как я объясняю в названии модульного теста, какое поведение тест тестирует в действительности, писать это в случае верблюда очень болезненно для чтения, поэтому я использую соглашение , подчеркнутое , , все нормально в Тесты .

@Test public void when_service_throw_Exception_InProgress_then_returns_false() throws Exception {
    // given
    MyBean bean = new MyBean();
    MyService service = mock(MyAdapterService.class);
    bean.setService(service);

    when(service.isInProgress()).thenThrow(new Exception());

    // when
    boolean result = bean.isInProgress();

    // then
    assertFalse(result);
}

Также я бы разделил утверждение о событии, это другое поведение:

@Test public void when_service_throw_Exception_InProgress_then_log_event_MDI09() throws Exception {
    // given
    MyBean bean = new MyBean();
    MyService service = mock(MyAdapterService.class);
    bean.setService(service);
    // somehow set up the logEvents collaborator

    when(service.isInProgress()).thenThrow(new Exception());

    // when
    bean.isInProgress();

    // then
    assertTrue(logEvents.containsMessage("MDI09"));
}

Вы даже можете пойти дальше, чтобы упростить прибор, если вы используете JUnit, вы пишете этот код:

@RunWith(MockitoJUnitRunner.class)
public class MyBeanTest {
    @Mock MyService service;
    @Mock LogEvents logEvents;
    @InjectMocks MyBean bean;


    @Test public void when_service_throw_Exception_InProgress_then_log_event_MDI09() throws Exception {
        // given
        when(service.isInProgress()).thenThrow(Exception.class);

        // when
        bean.isInProgress();

        // then
        verify(logEvents).logEvent("MDI09");
    }
}

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

...