JUnit Ожидаемый тест исключения: @Test(ожидается)

⚡ Умное резюме

JUnit Тестирование исключений подтверждает, что метод генерирует ошибку, которую он должен генерировать, используя необязательный параметр expected аннотации @Test. JUnit 4 и метод assertThrows в JUnit 5.

  • 🔘 Цель: Докажите, что некорректный ввод приводит к документированному исключению, а не к молчаливому неправильному ответу.
  • ☑️ Синтаксис: Метод `@Test(expected = ArithmeticException.class)` срабатывает только в том случае, если выбрасывается исключение именно такого типа.
  • ✅ Пример: JUnitСообщение делится на ноль, и AirthematicTest ожидает в результате исключение ArithmeticException.
  • 🧪 Альтернатива: Блок try, за которым следует fail(), позволяет проверить перехваченное исключение перед его проверкой.
  • 🇧🇷 JUnit 5: Функция assertThrows возвращает перехваченное исключение, поэтому можно проверить и сообщение, и причину его возникновения.
  • 📌 Ловушка: Ожидаемый параметр передается везде, где возникает исключение, что может скрывать ошибку в коде инициализации.

JUnit Проверка ожидаемого исключения с использованием параметра @Test(expected)

JUnit предоставляет возможность tracПроверьте наличие исключения и убедитесь, что код генерирует ожидаемое исключение.

JUnit Пункт 4 предоставляет простой и понятный способ тестирования исключений. Вы можете использовать:

  • Необязательный параметр (ожидаемый) @Тестовая аннотация и
  • к tracДля получения этой информации можно использовать функцию «fail()».

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

Пример: @Test(expected = IllegalArgumentException.class)

С помощью параметра «expected» можно указать имя исключения, которое может быть сгенерировано нашим тестом. В приведенном выше примере используется «IllegalArgumentException«Этот сигнал будет выдан тестом, если разработчик использует недопустимый аргумент».

Пример использования @Test(expected)

Давайте разберемся с тестированием исключений, создав Java класс с методом, который генерирует исключение исключениеВы будете работать с этим и проверять это на тестовом занятии. Рассмотрите... JUnitВ файле Message.java есть метод, выполняющий математическую операцию. Деление в строке 14 приводит к делению на ноль, поэтому метод всегда генерирует исключение «ArithmeticException». См. ниже:

JUnitКласс сообщений в Eclipse в строке 14 происходит деление printMessage на ноль

package guru99.junit;

public class JUnitMessage{

	private String message;

	public JUnitMessage(String message) {
		this.message = message;
	}

public void printMessage(){

	System.out.println(message); 
	int divide=1/0;

}

public String printHiMessage(){ 

	message="Hi!" + message;
	
	System.out.println(message);

	return message;
}

}

Code Объяснение:

  • Code Линия 7: Создание параметризованного конструктора с инициализацией полей.
  • Code Линия 11-14: Создание метода для выполнения математической операции.
  • Code Линия 18: Создание другого метода для печати сообщения.
  • Code Линия 20: Создание новой строки для печати сообщения.
  • Code Линия 22: Вывод нового сообщения, созданного в строке 20.

Давайте создадим тестовый класс для вышеописанного. Java класс для проверки исключения.

Ниже представлен тестовый класс, который проверяет исключение (в данном случае ArithmeticException), выбрасываемое в результате выполнения вышеуказанного кода. Java учебный класс:

AirthematicTest.java

На скриншоте ниже показан тот же тест в редакторе, где файл сохранен как AirthematicTest1, а ожидаемый параметр выделен в строке 13:

Класс AirthematicTest1 в Eclipse с выделенной строкой @Test(expected = ArithmeticException.class)

package guru99.junit;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

public class AirthematicTest {

	public String message = "Saurabh";
	
	JUnitMessage junitMessage = new JUnitMessage(message);
	
	@Test(expected = ArithmeticException.class)
	public void testJUnitMessage(){

		System.out.println("Junit Message is printing ");
		junitMessage.printMessage();

	}

	@Test
	public void testJUnitHiMessage(){ 
		message="Hi!" + message;
		System.out.println("Junit Message is printing ");
		assertEquals(message, junitMessage.printHiMessage());
	
	}
}

Code Объяснение:

  • Code Линия 13: Для создания теста мы используем аннотацию `@Test`. При выполнении метода указанного выше класса будет выполняться математическая операция. В данном случае ожидается исключение `ArithmeticException`, поэтому мы указываем его в качестве параметра в `@Test`.
  • Code Линия 17: Вызов функции printMessage() из JUnitСообщение.java.
  • Code Линия 21-22: Создаем еще один тестовый метод для проверки сообщения "Hi", на этот раз без ожидаемого параметра.

Класс содержит два тестовых метода, поэтому за один запуск выполняются оба: тот, который ожидает ArithmeticException, и тот, который проверяет возвращаемую строку.

Примечание: В исходном материале этот пример представлен под тремя разными именами: в листинге класс называется AirthematicTest, на скриншоте редактора отображается AirthematicTest1, а в результатах поиска — JunitTestExample. Код в обоих случаях идентичен; отличается только имя файла.

Давайте выполним это и проверим результат. JUnit Ниже представлены отчеты о ходе выполнения JunitTestExample.java.

Выход:

Вот результат, подтверждающий успешное проведение теста без сбоев. trace, как указано ниже:

Eclipse JUnit Просмотр отчетов. Выполнено 2 из 2 тестов без ошибок и сбоев для JunitTestExample.

Оба метода работают корректно. Первый проходит успешно, потому что действительно возникло исключение ArithmeticException, а второй — потому что возвращенная строка совпадает. Если бы при делении исключение не возникло, JUnit Первый метод завершился бы ошибкой с сообщением «Ожидаемое исключение: java.lang.ArithmeticException».

Три способа проверить наличие исключения в JUnit 4

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

Подход Утверждает ли это сообщение? Определяет ли линия броска? лучше всего для
@Test(expected = X.class) Нет Нет — любая строка в методе может вызвать исключение. Короткие тесты, в которых важен только тип исключения.
try / fail() / catch Да, внутри блока catch. Да — отслеживается только охраняемый звонок. Тесты, которые должны проверить сообщение или причину.
@Rule ExpectedException Да, через expectMessage() Нет Устаревшие пакеты программного обеспечения уже построены на основе правил.

Идиома функции fail(), упомянутая во введении, выглядит следующим образом. Если вызов не вызывает исключение, функция fail() выполняется, и тест выводит сообщение, которое вы написали:

@Test
public void testDivideByZero() {
    try {
        junitMessage.printMessage();
        fail("Expected an ArithmeticException");
    } catch (ArithmeticException e) {
        assertEquals("/ by zero", e.getMessage());
    }
}

Правило ExpectedException находится между ними. Оно было признано устаревшим в JUnit 4.13 в пользу метода assertThrows, описанного далее, поэтому новый JUnit 4 теста не следует его использовать.

Как тестировать исключения в JUnit 5 с помощью assertThrows()

JUnit В пункте 5 полностью удаляется ожидаемый параметр из @Test. Jupiter предоставляет assertThrows()Функция принимает класс исключения и лямбда-функцию, содержащую тестируемый код. Она возвращает перехваченное исключение, поэтому сообщение, причина и любые пользовательские поля могут быть проверены впоследствии.

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;

public class AirthematicJupiterTest {

    JUnitMessage junitMessage = new JUnitMessage("Saurabh");

    @Test
    public void testJUnitMessage() {
        ArithmeticException thrown = assertThrows(
                ArithmeticException.class,
                () -> junitMessage.printMessage());
        assertEquals("/ by zero", thrown.getMessage());
    }
}

Три связанных утверждения дополните семью:

  • assertThrows Принимает исключение указанного типа или любой его подкласс.
  • assertThrowsExactly Отклоняет подкласс, поэтому проходит проверку только именованный тип.
  • assertDoesNotThrow Это противоречит предыдущему ожиданию, а именно, что выполнение блока завершится без ошибок.

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

Распространенные ошибки при тестировании исключений в JUnit

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

Симптом Вызывать фиксированный
Ожидаемое исключение: java.lang.ArithmeticException Метод был успешно завершен без ошибок. Убедитесь, что входные данные действительно недействительны, затем запустите программу повторно.
Тест пройден, но выдана неправильная строка. Ожидаемый параметр отслеживает весь процесс, включая настройку. Перенесите настройку в другое место или используйте assertThrows вместо одного вызова.
Необработанное исключение в редакторе. Выбрасывается проверяемое исключение, но оно никогда не объявляется. Добавьте вызовы исключений (throws) в сигнатуру тестового метода.
Тест проходит проверку подкласса, который вы не планировали использовать. Функция assertThrows принимает подклассы указанного типа. Используйте assertThrowsExactly для строгого соответствия типов.
атрибут expected не является допустимым. Тест был составлен с использованием аннотации Jupiter @Test. Импортируйте org.junit.Test для JUnit 4, или перейти к assertThrows.

Последняя строка чаще всего вызывает затруднения у пользователей во время миграции, потому что обе аннотации называются @Test, и только импорт позволяет их различить.ping one JUnit версия на прецедент Этот класс позволяет избежать всей проблемы в целом.

Часто задаваемые вопросы (FAQ)

Ожидаемый параметр не может проверять сообщение. Оберните вызов в блок try, вызовите fail() сразу после него и проверьте getMessage() внутри блока catch. JUnit В пункте 5 это упрощается, поскольку assertThrows возвращает перехваченное исключение.

JUnit Тест не проходит и выдает сообщение «Ожидаемое исключение», за которым следует указанный вами класс. Больше ничего не сообщается, поэтому тест, который никогда не выдает исключение, выглядит идентично тесту, поведение которого в рабочем коде незаметно изменилось.

Искусственный интеллект-ассистенты считывают код метода, перечисляют входные данные, которые приводят к каждому оператору throw, и составляют тест для каждой ветви. Рассматривая выходные данные как отправную точку, ассистент определяет тип исключения по коду, поэтому неправильное исключение throw точно копируется в тест.

Copilot Используется тот стиль, который уже существует в файле, поэтому в проекте со смешанным стилем будет использоваться тот же стиль. Перед принятием предложения проверьте строку импорта, поскольку org.junit.Test и org.junit.jupiter.api.Test выглядят одинаково в редакторе.

Оно всё ещё существует, но было признано устаревшим в 2000 году. JUnit 4.13, так и не был портирован на Jupiter. Существующие наборы тестов могут его сохранить; в новых тестах следует использовать assertThrows, который читается лучше и не требует публичного поля правила.

Да. Параметр лямбда-функции — это исполняемый объект (Executable), который объявлен как генерирующий исключение типа Throwable, поэтому для проверяемого исключения не требуется условие throws в самом тестовом методе. То же самое относится и к JUnit 4. Попробуйте поймать идиому.

Функция assertThrows принимает любой подкласс указанного типа, поэтому при ожидании RuntimeException также передается NullPointerException. Используйте assertThrowsExactly, когда важен точный класс, или укажите наиболее узкий тип, который вы ожидаете.

Только в тех случаях, когда исключение является частью соглашения.tract. При тестировании исключения метод никогда не гарантирует сгенерировать блокировки в случае случайного поведения, что затрудняет рефакторинг и сводит на нет смысл теста.

Подведем итог этой публикации следующим образом: