Я знаю, что один из способов сделать это будет:
@Test
public void foo(){
try{
//execute code that you expect not to throw Exceptions.
}
catch(Exception e){
fail("Should not have thrown any exception");
}
}
Есть ли более чистый способ сделать это? (Вероятно, используя Junit's @Rule
?)
java
unit-testing
junit
exception-handling
junit4
Анкит Дингра
источник
источник
Ответы:
Вы подходите к этому неправильно. Просто проверьте свою функциональность: если сгенерировано исключение, тест автоматически провалится. Если исключение не выдано, все ваши тесты станут зелеными.
Я заметил, что этот вопрос вызывает интерес время от времени, поэтому я буду немного расширяться.
Предпосылки к юнит-тестированию
Когда вы проводите модульное тестирование, важно определить для себя, что вы считаете единицей работы. В основном: извлечение вашей кодовой базы, которая может включать или не включать несколько методов или классов, представляющих один элемент функциональности.
Или, как определено в «Искусстве модульного тестирования», 2-е издание Роя Ошерова , стр. 11:
Важно понимать, что одна единица работы обычно не просто один метод, но на самом базовом уровне это один метод, и после этого он инкапсулируется другой единицей работ.
В идеале у вас должен быть метод тестирования для каждой отдельной единицы работы, чтобы вы всегда могли сразу увидеть, где что-то идет не так. В этом примере есть базовый метод,
getUserById()
который будет возвращать пользователя, и всего будет 3 единицы работ.Первая единица работы должна проверить, возвращается ли верный пользователь в случае правильного и недействительного ввода.
Любые исключения, которые вызываются источником данных, должны быть обработаны здесь: если ни один пользователь не присутствует, должен быть тест, который демонстрирует, что исключение выдается, когда пользователь не может быть найден. Примером этого может быть тот,
IllegalArgumentException
который пойман с@Test(expected = IllegalArgumentException.class)
аннотацией.После того, как вы обработали все свои варианты использования для этой основной единицы работы, вы переходите на новый уровень. Здесь вы делаете то же самое, но вы обрабатываете только исключения, которые приходят с уровня прямо под текущим. Это сохраняет ваш тестовый код хорошо структурированным и позволяет быстро бегать по архитектуре, чтобы найти, где что-то идет не так, вместо того, чтобы прыгать повсюду.
Обработка правильного и ошибочного ввода теста
На данный момент должно быть ясно, как мы будем обрабатывать эти исключения. Существует 2 типа ввода: допустимый ввод и неправильный ввод (ввод в строгом смысле действителен, но не корректен).
Когда вы работаете с правильным вводом, вы устанавливаете неявное ожидание того, что любой тест, который вы напишите, сработает.
Такой способ вызова может выглядеть следующим образом :
existingUserById_ShouldReturn_UserObject
. Если этот метод не срабатывает (например, выдается исключение), то вы знаете, что что-то пошло не так, и вы можете начать копать.Добавив еще один метод test (
nonExistingUserById_ShouldThrow_IllegalArgumentException
), который использует ошибочный ввод и ожидает исключения, вы можете увидеть, делает ли ваш метод то, что он должен делать с неправильным вводом.TL; DR
Вы пытались сделать две вещи в своем тесте: проверить правильность и ошибочность ввода. Разделив это на два метода, каждый из которых выполняет одну задачу, вы получите намного более четкие тесты и гораздо лучший обзор того, где что-то идет не так.
Имея в виду многоуровневую единицу работ, вы также можете уменьшить количество тестов, необходимых для слоя, который находится выше в иерархии, потому что вам не нужно учитывать все, что могло бы пойти не так на нижних уровнях: Уровни ниже текущего являются виртуальной гарантией того, что ваши зависимости работают, и если что-то пойдет не так, это на вашем текущем уровне (при условии, что нижние уровни сами не выдают ошибок).
источник
expected
аннотацию. Если вы хотите протестировать сценарий, в котором ваш код дает сбой, и вы хотите увидеть, правильно ли обрабатывается ошибка: используйтеexpected
и, возможно, используйте утверждения, чтобы определить, была ли она устранена.throws IllegalArgumentException
в свой тест. В итоге вы хотите, чтобы ваш тест стал красным, если есть исключение. Ну, угадай что? Вам не нужно писатьfail()
. Как писал @Jeroen Vannevel: «ЕслиЯ наткнулся на это из-за правила SonarQube «squid: S2699»: «Добавьте хотя бы одно утверждение в этот контрольный пример».
У меня был простой тест, единственной целью которого было пройти без исключений.
Рассмотрим этот простой код:
Какое утверждение можно добавить для проверки этого метода? Конечно, вы можете попытаться обойти это, но это только раздувание кода.
Решение исходит от самого JUnit.
Если исключение не выдается, и вы хотите явно проиллюстрировать это поведение, просто добавьте,
expected
как в следующем примере:Test.None.class
по умолчанию для ожидаемого значения.источник
С AssertJ беглые утверждения 3.7.0 :
источник
JUnit 5 (Jupiter) предоставляет три функции для проверки отсутствия / присутствия исключений:
●
assertAll()
Утверждает, что все предоставленные
executables
не генерируют исключения.
●
assertDoesNotThrow()
Утверждает, что выполнение
предоставленного
executable
/supplier
не вызывает каких-либо исключений .
Эта функция доступна
с JUnit 5.2.0 (29 апреля 2018 г.).
●
assertThrows()
Утверждает , что выполнение подаваемы
executable
бросает исключение из
expectedType
и возвращает исключение .
пример
источник
Java 8 делает это намного проще, а Kotlin / Scala вдвойне.
Мы можем написать немного полезного класса
и тогда ваш код становится просто:
Если у вас нет доступа к Java-8, я бы использовал болезненно старую утилиту Java: блоки кода и простой комментарий
И наконец, с kotlin, языком, в который я недавно влюбился:
Хотя есть много места, чтобы возиться с тем, как именно вы хотите выразить это, я всегда был поклонником беглых утверждений .
относительно
Это правильно в принципе, но неверно в заключение.
Java допускает исключения для потока управления. Это выполняется самой средой выполнения JRE в API, например,
Double.parseDouble
через aNumberFormatException
иPaths.get
через aInvalidPathException
.Учитывая, что вы написали компонент, который проверяет числовые строки, например
Double.ParseDouble
, используя Regex, может быть, рукописный парсер, или, возможно, что-то, что включает в себя некоторые другие доменные правила, которые ограничивают диапазон двойных значений чем-то конкретным, как лучше всего это проверить составная часть? Я думаю, что очевидным тестом было бы утверждать, что при разборе результирующей строки исключение не выдается. Я написал бы этот тест, используя либо выше,assertDoesNotThrow
либо/*comment*/{code}
блок. Что-то вродеЯ также призываю вас параметризировать этот тест при
input
использованииTheories
илиParameterized
чтобы вы могли более легко повторно использовать этот тест для других входных данных. В качестве альтернативы, если вы хотите заняться экзотикой, вы можете использовать инструмент генерации тестов (и это ). TestNG лучше поддерживает параметризованные тесты.Что я нахожу особенно неприятным, так это рекомендация использования
@Test(expectedException=IllegalArgumentException.class)
, это исключение опасно широкое . Если ваш код изменяется так, как это имеет конструктор тестируемого компонентаif(constructorArgument <= 0) throw IllegalArgumentException()
, и ваш тест предоставлял 0 для этого аргумента, потому что это было удобно - и это очень часто, потому что хорошая генерация тестовых данных - это удивительно трудная проблема - тогда ваш тест будет зеленая полоса, даже если она ничего не проверяет. Такой тест хуже бесполезного.источник
Assert.assertThrows
чтобы проверить, что некоторый код вызывает исключение.Если вам не повезло поймать все ошибки в вашем коде. Ты можешь тупо сделать
источник
Exception ex
должно быть,= null;
прежде чем вы сможете проверить его.JUnit5 добавляет метод assertAll () именно для этой цели.
Источник: JUnit 5 API
источник
Хотя этому посту уже 6 лет, в мире Junit многое изменилось. С Junit5, теперь вы можете использовать
Пример:
Надеюсь, что это поможет людям, которые используют более новую версию Junit5
источник
Awaitility
«SuntilAsserted(ThrowingRunnable assertion)
. Тестируемая система в настоящий момент выдает конкретное исключение в ThrowingRunnable, который я предоставляю, но я хочу дать ему некоторое время, пока он не прекратит это делать. Однако, если это вызовет другое исключение, я бы хотел, чтобы тест мгновенно провалился.Если вы хотите проверить, использует ли ваша цель тестирования исключение. Просто оставьте тест как (издевайтесь над сотрудником, используя jMock2):
Тест пройдёт, если ваша цель использует выброшенное исключение, иначе тест не пройдёт.
Если вы хотите проверить логику потребления исключений, все усложняется. Я предлагаю делегировать потребление сотруднику, который может быть осмеян. Поэтому тест может быть:
Но иногда это чрезмерно разработано, если вы просто хотите войти. В данном случае эта статья ( http://java.dzone.com/articles/monitoring-declarative-transac , http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there -an-easy-way / ) может помочь, если в этом случае вы настаиваете tdd.
источник
Используйте assertNull (...)
источник
assertNull
никогда не выполняется. Однако у быстрого читателя создается впечатление, что сделано утверждение, которое действительно проверяет случай без броска. Другими словами: если достигнут блок catch, исключение всегда ненулевое - его можно заменить простымfail
.assertNull(e)
сообщит о том, что тест не пройден, поскольку, как указано,e
не может бытьnull
вcatch
блоке ... Майк, это просто странное программирование: - /. .. да хотя бы использовать,fail()
как говорит АндреасВы можете ожидать, что исключение не выдается, создавая правило.
источник
Это, возможно, не лучший способ, но он определенно гарантирует, что исключение не выдается из тестируемого блока кода.
источник
Вы можете сделать это с помощью @Rule, а затем вызвать метод reportMissingExceptionWithMessage, как показано ниже: Это код Scala.
источник
private val
? Что это за язык? Ясно, что не Java; p И, пожалуйста, не предоставляйте код в качестве скриншота, это не приветствуется.Следующее не проходит проверку для всех исключений, отмеченных или не проверенных:
источник
Вы можете создавать любые собственные утверждения на основе утверждений из junit:
И проверить:
Вообще говоря, существует возможность мгновенного провала («бла бла бла») теста в любых сценариях, в любом месте, где это имеет смысл. Например, используйте его в блоке try / catch, чтобы потерпеть неудачу, если в тестовом примере что-то было выброшено:
Это пример метода, который мы тестируем. Предположим, у нас есть такой метод, который не должен давать сбой при определенных обстоятельствах, но может давать сбой:
Вышеуказанный метод является простым примером. Но это работает для сложных ситуаций, где отказ не так очевиден. Есть импорт:
источник