Условно игнорируем тесты в JUnit 4

365

Итак, @Ignoreаннотация хороша для обозначения того, что тестовый пример не должен выполняться.

Однако иногда я хочу игнорировать тест, основанный на информации времени выполнения. Примером может быть, если у меня есть тест параллелизма, который должен быть запущен на машине с определенным количеством ядер. Если бы этот тест выполнялся на однопроцессорной машине, я не думаю, что было бы правильно просто пройти тест (так как он не был запущен), и, конечно, было бы неправильно проваливать тест и нарушать сборку. ,

Поэтому я хочу иметь возможность игнорировать тесты во время выполнения, так как это выглядит как правильный результат (поскольку среда тестирования позволит выполнить сборку, но записать, что тесты не выполнялись). Я вполне уверен, что аннотация не даст мне такой гибкости, и подозреваю, что мне нужно будет вручную создать набор тестов для рассматриваемого класса. Однако в документации ничего не говорится об этом, и, просматривая API , также неясно, как это будет сделано программно (то есть, как мне программно создать экземплярTest или аналог, который эквивалентен тому, который создан @Ignoreаннотацией?).

Если кто-то делал что-то подобное в прошлом или имел блестящее представление о том, как еще я мог бы пойти по этому поводу, я был бы рад услышать об этом.

Анджей Дойл
источник

Ответы:

476

Способ JUnit состоит в том, чтобы сделать это во время выполнения org.junit.Assume.

 @Before
 public void beforeMethod() {
     org.junit.Assume.assumeTrue(someCondition());
     // rest of setup.
 }

Вы можете сделать это в @Beforeметоде или в самом тесте, но не в @Afterметоде. Если вы сделаете это в самом тесте, ваш @Beforeметод запустится. Вы также можете сделать это внутри, @BeforeClassчтобы предотвратить инициализацию класса.

Предположительный сбой приводит к игнорированию теста.

Изменить: Для сравнения с @RunIfаннотацией из junit-ext , их пример кода будет выглядеть следующим образом:

@Test
public void calculateTotalSalary() {
    assumeThat(Database.connect(), is(notNull()));
    //test code below.
}

Не говоря уже о том, что Database.connect()таким способом намного проще захватить и использовать соединение из метода.

Ишай
источник
1
@ notnoop, это не мое наблюдение вообще. Они игнорируются. Бегущий по тестам IDEA сообщает о них таким образом, и взгляд на исходный код JUnit показывает, что он сообщает о том, что тест проигнорирован.
Ишай
1
Процитирую: «В будущем это может измениться, и ошибочное предположение может привести к игнорированию теста». На самом деле он изменился, на 4.5 я верю. Текущий Javadoc говорит: «Бегун JUnit по умолчанию рассматривает тесты с ошибочными предположениями как проигнорированные. Пользовательские бегуны могут вести себя по-другому». github.com/KentBeck/junit/blob/…
Ишай
4
Eclipse 3.6 с Junit 4.8.1 сообщает о ложных предположениях как о прохождении теста. То же самое с муравьем 1.8.1.
2010 года
8
То, что Eclipse сообщает о сбойных
Martin
1
@JeffStorey, тогда вы ищете пару вещей. Одним из них является @BeforeClassаннотация, где вы можете потерпеть неудачу в своем предположении, что пропустит весь класс. Другое @ClassRule(для мелкозернистого контроля, но для всего класса, один раз).
Ишай
51

Вы должны оформить заказ Junit-ext. У них есть RunIfаннотация, которая выполняет условные тесты, такие как:

@Test
@RunIf(DatabaseIsConnected.class)
public void calculateTotalSalary() {
    //your code there
}

class DatabaseIsConnected implements Checker {
   public boolean satisify() {
        return Database.connect() != null;
   }
}

[Пример кода взят из их учебника]

notnoop
источник
3
Спасибо за этот ответ - интересный альтернативный синтаксис для функциональности, хотя я буду идти Assumeнепосредственно, чтобы не вводить другую зависимость.
Анджей Дойл
3
Я лично предпочитаю это решение. Если у вас есть много тестов, которые должны выполняться на основе одних и тех же условий, это было бы гораздо более идеальным, чем использование Assume в каждом тесте. Кроме того, если это можно использовать на уровне класса, а не на уровне метода, это будет еще более идеальным.
Ричард
Я бы предпочел, потому что это помогает выполнить тест условно во время выполнения. Он подходит для тех случаев, когда будет выполняться несколько модульных тестов, и требуется запускать модульные тесты для определенной программы проверки. Я действительно поражен, увидев, что junit-ext недоступен в репозитории maven. Как бы мы воспользовались этим в проекте Maven.
Шамбху
4
Подобная аннотация @RunIfотделяет условие, когда тест должен выполняться от фактического кода теста, что я считаю хорошим. Что мне не нравится, так это то, что для этого нужен конкретный участник теста. Поэтому я написал правило JUnit для условного игнорирования тестов.
Рюдигер Херрманн
2
После установки jar junit-ext (находится здесь code.google.com/p/junit-ext/downloads/… ) в нашем локальном репозитории и реализации этой аннотации @RunIf ... ничего! Это полностью игнорируется, и я думаю, что причина может заключаться в том, что junit-ext, кажется, зависит от junit 4.5. Нам нужно 4,9+ из-за весенних испытаний. Так что ... не бери в голову это.
Марк
7

В JUnit 4 другой вариант для вас может состоять в том, чтобы создать аннотацию, обозначающую, что тест должен соответствовать вашим настраиваемым критериям, а затем расширить бегун по умолчанию своим собственным и, используя рефлексию, основывать свое решение на пользовательских критериях. Это может выглядеть примерно так:

public class CustomRunner extends BlockJUnit4ClassRunner {
    public CTRunner(Class<?> klass) throws initializationError {
        super(klass);
    }

    @Override
    protected boolean isIgnored(FrameworkMethod child) {
        if(shouldIgnore()) {
            return true;
        }
        return super.isIgnored(child);
    }

    private boolean shouldIgnore(class) {
        /* some custom criteria */
    }
}
Кайл Шрейдер
источник
Хотя это выглядит красиво и понятно, с JUnit4 оно не работает с текущими версиями, поскольку метод больше BlockJUnit4ClassRunnerне предлагает этот isIgnoredметод.
Дейв
-2

Быстрое примечание: Assume.assumeTrue(condition)игнорирует остальные шаги, но проходит тест. Чтобы провалить тест, используйте org.junit.Assert.fail()внутри условного оператора. Работает так же, как, Assume.assumeTrue()но не проходит тест.

Тин тин
источник
5
Как отмечалось в ответах выше, ошибочное предположение не приводит к прохождению теста, оно возвращает отдельный статус. Некоторые бегуны могут ошибочно сообщить об этом, как если бы это был проход, но это слабость / ошибка в тестере (и бегун JUnit по умолчанию отображает тест как проигнорированный). И что касается вашего последнего предложения, провал теста определенно не то, что я хочу (ред), чтобы сделать.
Анджей Дойл
О хорошо В моем случае тесты проходили с ошибочным предположением, но я хотел, чтобы о них сообщали как о неудачных (я проверял исключение из Test Watcher). Принудительный отказ помог мне.
Tin TIn