Убедитесь, что метод был вызван и прервал выполнение/игнорировал более поздние сбои

У меня есть тест, в котором я написал большую часть необходимых мне модульных тестов, но есть один, в котором я хочу протестировать первые биты логики. Меня не волнует, что происходит в остальной части метода, пока метод вызывается, но поскольку SUT терпит неудачу с NPE из-за отсутствия дальнейших насмешек, тест терпит неудачу прежде, чем я доберусь до своего утверждения.

Существует ли чистый способ подтверждения вызова метода и игнорирования всех исключений, происходящих после этого? Возможно, какое-то блокирующее поведение при попадании в метод и прерывании/прохождении теста после этого?

Я думал, что могу написать when(mock.methodIAmInterestedIn(any)).thenThrow(new RuntimeException("verified!")), а затем просто утверждать, что получаю правильное исключение (однако оно будет заключено в другое). Это, вероятно, сработает, но это немного нечисто: скрывает то, что я действительно хочу проверить.

@Test
public void should_load_using_filename_in_config() {
    loader = new OrgUnitLoader(config, dbSupport.mockServices);
    config = mock(TestConfiguration.class);
    /* further mocking of the config needed if I am not to get an NPE */

    when(dao.orgUnitsAreLoaded()).thenReturn(false);

    // call the actual method
    loader.loadOrgUnits();

    verify(config, times(1)).getString(ORG_UNIT_DATA_FILE);
}

Например, можно ли использовать CountdownLatch?


person oligofren    schedule 27.06.2018    source источник


Ответы (3)


Я хочу проверить первые биты логики. Мне все равно, что происходит в остальной части метода

Похоже, ваш тестируемый код не соответствует шаблону единой ответственности.

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


есть два очевидных минуса:

  1. Затем мне нужно будет открыть SUT, превратив множество внутренних методов, которые, естественно, должны быть закрытыми, в методы с пакетным доступом, чтобы иметь возможность их протестировать. – олигофрен

Дело в том, что существует очевидная необходимость проверять поведение отправки независимо от фактической бизнес-логики, заложенной в текущий метод. Это говорит мне о том, что это поведение отправки является собственной ответственностью, которая должна быть отделена от остального или метода.

Мне кажется, что вся остальная логика принадлежит другим классам, а не только отдельным методам в том же классе. Это следствие принципа Один и тот же уровень абстракции, который мы должны применять как к классам, так и к методам. Эти новые классы действительно обеспечивают по крайней мере package private доступ к своему интерфейсу.

  1. Я был бы очень сильно привязан к внутренностям ТРИ, но, наверное, я уже это делаю… — олигофрен

Эта «жесткая привязка» может существовать только в вашей голове, зная фактическую реализацию. Тот факт, что вам нужно разделить код для тестирования, показывает, что код менее жестко ограничен, как вы думаете.

Я предполагаю, что во всех решениях по модульному тестированию присутствует определенный прагматизм (код только для тестирования, открытие,...). – олигофрен

Существует довольно простое правило юнит-тестирования, которое позволяет избежать всех этих «прагматических решений»:

UnitTest не тестирует код, UnitTest проверяет общедоступное наблюдаемое поведение, где общедоступное означает: возвращаемые значения и < em>связь с зависимостями.

Здесь нет места «прагматичным решениям». Единственное решение: каково ожидаемое поведение CUT?

person Timothy Truckle    schedule 27.06.2018
comment
Я согласен, что это было бы лучше, но есть два очевидных недостатка: 1. Затем мне нужно было бы открыть SUT, превратив множество внутренних методов, которые, естественно, должны быть private, в методы с пакетным доступом, чтобы иметь возможность их протестировать. 2. Я был бы очень тесно связан с внутренностями SUT, но я думаю, что я уже делаю это ... Я думаю, что во всех решениях модульного тестирования присутствует определенный прагматизм (код только для тестирования, открытие, ...). - person oligofren; 27.06.2018

Почему вы не используете CompletableFuture, вы можете создать экземпляр этого класса с конструктором без аргументов для представления некоторого будущего результата, передать его потребителям и завершить его в какое-то время в будущем, используя метод complete. Потребители могут использовать метод get для блокировки текущего потока до тех пор, пока не будет предоставлен этот результат.

person YohanT    schedule 27.06.2018
comment
Пожалуйста, ознакомьтесь с этими пояснениями: baeldung.com/java-completablefuture - person YohanT; 28.06.2018

Поскольку вы знаете, что ваш тестовый загрузчик/конфигурация неполный, вы ожидаете, что метод в какой-то момент не сработает. Учтите это в своем тесте:

@Test
public void should_load_using_filename_in_config() {
    loader = new OrgUnitLoader(config, dbSupport.mockServices);
    config = mock(TestConfiguration.class);
    /* further mocking of the config needed if I am not to get an NPE */

    when(dao.orgUnitsAreLoaded()).thenReturn(false);

    try {
        // call the actual method
        loader.loadOrgUnits();
        Assert.fail("Should fail as config is incomplete.");
    } catch (NullPointerException e) {
        verify(config, times(1)).getString(ORG_UNIT_DATA_FILE);
    }

}

РЕДАКТИРОВАТЬ (после комментариев)

Перехват только ожидаемого NPE исключает другие исключения. Если NPE будет выброшен до вызова dao.orgUnitsAreLoaded(), verify(...) потерпит неудачу. Вы это заметите.

Может быть, это не очень сложно, но очень просто и легко (KISS) понять - даже позже другим.

@see Junit утверждает что-то после ожидания и обработки исключения

person LuCio    schedule 27.06.2018
comment
Что мне не нравится, так это то, что он может выйти из строя по целому ряду причин, в том числе по причинам, которых я не ожидал. Это делает тест плохим. - person oligofren; 27.06.2018
comment
Конечно. Поэтому, когда вы говорите, что ожидаете NPE, вы можете поймать только это. - person LuCio; 27.06.2018