Как вы можете утверждать, что в тестах JUnit 4 выдается определенное исключение?

StackOverflow https://stackoverflow.com/questions/156503

Вопрос

Как я могу использовать JUnit4 идиоматически, чтобы проверить, что какой-то код генерирует исключение?

Хотя я, конечно, могу сделать что-то вроде этого:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  boolean thrown = false;

  try {
    foo.doStuff();
  } catch (IndexOutOfBoundsException e) {
    thrown = true;
  }

  assertTrue(thrown);
}

Я помню, что есть аннотация или Assert.xyz или что-нибудь это гораздо менее запутанно и гораздо более соответствует духу JUnit для подобных ситуаций.

Это было полезно?

Решение

JUnit 4 поддерживает это:

@Test(expected = IndexOutOfBoundsException.class)
public void testIndexOutOfBoundsException() {
    ArrayList emptyList = new ArrayList();
    Object o = emptyList.get(0);
}

Ссылка: https://junit.org/junit4/faq.html#atests_7

Другие советы

Редактировать Теперь, когда выпущен JUnit5, лучшим вариантом будет использовать Assertions.assertThrows() (видеть мой другой ответ).

Если вы еще не перешли на JUnit 5, но можете использовать JUnit 4.7, вы можете использовать ExpectedException Правило:

public class FooTest {
  @Rule
  public final ExpectedException exception = ExpectedException.none();

  @Test
  public void doStuffThrowsIndexOutOfBoundsException() {
    Foo foo = new Foo();

    exception.expect(IndexOutOfBoundsException.class);
    foo.doStuff();
  }
}

Это намного лучше, чем @Test(expected=IndexOutOfBoundsException.class) потому что тест не пройдёт, если IndexOutOfBoundsException бросается раньше foo.doStuff()

Видеть Эта статья для подробностей

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

Я обычно использую это для проверки параметров тестирования, потому что такие методы обычно очень просты, но для более сложных тестов лучше использовать:

try {
    methodThatShouldThrow();
    fail( "My method didn't throw when I expected it to" );
} catch (MyException expectedException) {
}

Примените суждение.

Как уже говорилось ранее, существует множество способов обработки исключений в JUnit.Но в Java 8 есть еще один:использование лямбда-выражений.С помощью лямбда-выражений мы можем добиться такого синтаксиса:

@Test
public void verifiesTypeAndMessage() {
    assertThrown(new DummyService()::someMethod)
            .isInstanceOf(RuntimeException.class)
            .hasMessage("Runtime exception occurred")
            .hasMessageStartingWith("Runtime")
            .hasMessageEndingWith("occurred")
            .hasMessageContaining("exception")
            .hasNoCause();
}

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

Это относительно простой, но мощный метод.

Взгляните на этот пост в блоге, описывающий эту технику: http://blog.codeleak.pl/2014/07/junit-testing-Exception-with-java-8-and-lambda-expressions.html

Исходный код можно найти здесь: https://github.com/kolorobot/unit-testing-demo/tree/master/src/test/java/com/github/kolorobot/Exceptions/java8

Раскрытие информации:Я автор блога и проекта.

в junit есть четыре способа проверки исключений.

  • для junit4.x используйте необязательный атрибут «expected» аннотации Test.

    @Test(expected = IndexOutOfBoundsException.class)
    public void testFooThrowsIndexOutOfBoundsException() {
        foo.doStuff();
    }
    
  • для junit4.x используйте правило ExpectedException

    public class XxxTest {
        @Rule
        public ExpectedException thrown = ExpectedException.none();
    
        @Test
        public void testFooThrowsIndexOutOfBoundsException() {
            thrown.expect(IndexOutOfBoundsException.class)
            //you can test the exception message like
            thrown.expectMessage("expected messages");
            foo.doStuff();
        }
    }
    
  • вы также можете использовать классический метод try/catch, широко используемый в рамках Junit 3.

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        try {
            foo.doStuff();
            fail("expected exception was not occured.");
        } catch(IndexOutOfBoundsException e) {
            //if execution reaches here, 
            //it indicates this exception was occured.
            //so we need not handle it.
        }
    }
    
  • наконец, для junit5.x вы также можете использовать AssertThrows следующим образом:

    @Test
    public void testFooThrowsIndexOutOfBoundsException() {
        Throwable exception = assertThrows(IndexOutOfBoundsException.class, () -> foo.doStuff());
        assertEquals("expected messages", exception.getMessage());
    }
    
  • так

    • первый способ используется, когда вы хотите проверить только тип исключения
    • остальные три способа используются, когда вы хотите продолжить тестирование сообщения об исключении
    • если используете junit 3, то предпочтительнее 3-й
    • если вам нравится 5-й июнь, то вам должен понравиться и 4-й
  • для получения дополнительной информации вы можете прочитать этот документ и руководство пользователя junit5 для получения подробной информации.

TL; доктор

  • до JDK8:Я порекомендую старое добро try-catch блокировать.(Не забудьте добавить fail() утверждение перед catch блокировать)

  • после JDK8:Используйте AssertJ или собственные лямбда-выражения для подтверждения. исключительный поведение.

Независимо от Junit 4 или JUnit 5.

длинная история

Можно написать самому сделай сам try-catch заблокировать или использовать инструменты JUnit (@Test(expected = ...) или @Rule ExpectedException Функция правила JUnit).

Но эти способы не так элегантны и плохо сочетаются. читабельность с точки зрения с другими инструментами.Более того, у инструментов JUnit есть некоторые подводные камни.

  1. А try-catch Вам нужно написать блок вокруг тестируемого поведения и записать утверждение в блоке catch. Это может быть хорошо, но многие считают, что этот стиль прерывает поток чтения теста.Также вам необходимо написать Assert.fail в конце try блокировать, иначе тест может пропустить одну сторону утверждений; ПМД, найти жуков или Сонар выявит такие проблемы.

  2. А @Test(expected = ...) Эта функция интересна тем, что вы можете написать меньше кода, и тогда написание этого теста предположительно будет менее подвержено ошибкам кодирования. Но этому подходу не хватает некоторых областей.

    • Если тесту необходимо проверить дополнительные параметры исключения, например причину или сообщение (хорошие сообщения об исключении действительно важны, точного типа исключения может быть недостаточно).
    • Кроме того, поскольку в методе заложено ожидание, в зависимости от того, как написан тестируемый код, неправильная часть тестового кода может выдать исключение, что приведет к ложному положительному результату теста, и я не уверен, что ПМД, найти жуков или Сонар даст подсказки по такому коду.

      @Test(expected = WantedException.class)
      public void call2_should_throw_a_WantedException__not_call1() {
          // init tested
          tested.call1(); // may throw a WantedException
      
          // call to be actually tested
          tested.call2(); // the call that is supposed to raise an exception
      }
      
  3. А ExpectedException Правило также является попыткой исправить предыдущие предостережения, но его использование немного неудобно, поскольку оно использует стиль ожидания, ИзиМок пользователи очень хорошо знают этот стиль.Возможно, для кого-то это будет удобно, но если вы будете следовать Развитие, основанное на поведении (БДД) или Упорядочить действие (ААА) принципы ExpectedException правило не вписывается в этот стиль письма.Кроме того, он может страдать от той же проблемы, что и @Test образом, в зависимости от того, где вы ожидаете.

    @Rule ExpectedException thrown = ExpectedException.none()
    
    @Test
    public void call2_should_throw_a_WantedException__not_call1() {
        // expectations
        thrown.expect(WantedException.class);
        thrown.expectMessage("boom");
    
        // init tested
        tested.call1(); // may throw a WantedException
    
        // call to be actually tested
        tested.call2(); // the call that is supposed to raise an exception
    }
    

    Даже ожидаемое исключение помещается перед оператором теста, оно нарушает поток чтения, если тесты соответствуют BDD или AAA.

    Также посмотрите это комментарий проблема по JUnit автора ExpectedException. JUnit 4.13-бета-2 даже осуждает этот механизм:

    Запрос на извлечение № 1519:Устареть ExpectedException

    Метод Assert.assertThrows обеспечивает более удобный способ проверки исключений.Кроме того, использование ExpectedException чревато ошибками при использовании с другими правилами, такими как TestWatcher, поскольку в этом случае важен порядок правил.

Таким образом, приведенные выше варианты имеют множество предостережений и явно не застрахованы от ошибок кодера.

  1. После создания этого ответа мне стало известно о проекте, который выглядит многообещающе. перехват исключения.

    Как сказано в описании проекта, он позволяет программисту написать беглую строку кода, перехватывающую исключение, и предлагать это исключение для последующего утверждения.И вы можете использовать любую библиотеку утверждений, например Хэмкрест или УтверждатьJ.

    Быстрый пример, взятый с главной страницы:

    // given: an empty list
    List myList = new ArrayList();
    
    // when: we try to get the first element of the list
    when(myList).get(1);
    
    // then: we expect an IndexOutOfBoundsException
    then(caughtException())
            .isInstanceOf(IndexOutOfBoundsException.class)
            .hasMessage("Index: 1, Size: 0") 
            .hasNoCause();
    

    Как видите, код действительно прост: вы ловите исключение в определенной строке, then API — это псевдоним, который будет использовать API AssertJ (аналогично использованию assertThat(ex).hasNoCause()...). В какой-то момент проект опирался на FEST-Assert, предка AssertJ.. РЕДАКТИРОВАТЬ: Кажется, в проекте готовится поддержка Lambdas для Java 8.

    На данный момент у этой библиотеки есть два недостатка:

    • На момент написания этой статьи следует отметить, что эта библиотека основана на Mockito 1.x, поскольку она создает макет тестируемого объекта за сценой.Поскольку Mockito все еще не обновлен эта библиотека не может работать с финальными классами или финальными методами.И даже если бы он был основан на Mockito 2 в текущей версии, для этого потребовалось бы объявить глобального производителя моков (inline-mock-maker), что-то, что может быть не тем, что вам нужно, поскольку у этого макетчика есть другие недостатки, чем у обычного макетчика.

    • Это требует еще одной тестовой зависимости.

    Эти проблемы не возникнут, если библиотека будет поддерживать лямбда-выражения, однако функциональность будет дублироваться набором инструментов AssertJ.

    Принимая все во внимание, если вы не хотите использовать инструмент перехвата исключений, я порекомендую старый добрый способ try-catch блок, по крайней мере, до JDK7.А для пользователей JDK 8 вы можете предпочесть использовать AssertJ, поскольку он предлагает больше, чем просто утверждение исключений.

  2. С JDK8 на сцену тестирования выходят лямбды, которые оказались интересным способом обеспечить исключительное поведение.AssertJ был обновлен, чтобы предоставить удобный гибкий API для подтверждения исключительного поведения.

    И образец теста с УтверждатьJ :

    @Test
    public void test_exception_approach_1() {
        ...
        assertThatExceptionOfType(IOException.class)
                .isThrownBy(() -> someBadIOOperation())
                .withMessage("boom!"); 
    }
    
    @Test
    public void test_exception_approach_2() {
        ...
        assertThatThrownBy(() -> someBadIOOperation())
                .isInstanceOf(Exception.class)
                .hasMessageContaining("boom");
    }
    
    @Test
    public void test_exception_approach_3() {
        ...
        // when
        Throwable thrown = catchThrowable(() -> someBadIOOperation());
    
        // then
        assertThat(thrown).isInstanceOf(Exception.class)
                          .hasMessageContaining("boom");
    }
    
  3. После почти полного переписывания JUnit 5 утверждения были улучшен немного, они могут оказаться интересными как нестандартный способ правильно утверждать исключение.Но на самом деле API утверждений все еще немного скуден, снаружи ничего нет. assertThrows.

    @Test
    @DisplayName("throws EmptyStackException when peeked")
    void throwsExceptionWhenPeeked() {
        Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek());
    
        Assertions.assertEquals("...", t.getMessage());
    }
    

    Как вы заметили assertEquals все еще возвращается void, и поэтому не позволяет объединять утверждения, такие как AssertJ.

    Также, если вы помните, что имя конфликтует с Matcher или Assert, будьте готовы встретить такое же столкновение с Assertions.

Я хотел бы заключить, что сегодня (2017-03-03) УтверждатьJпростота использования, доступный API, быстрые темпы разработки и де-факто тестовая зависимость — лучшее решение для JDK8 независимо от тестовой среды (JUnit или нет), вместо этого предыдущие JDK должны полагаться на try-catch блоки, даже если они кажутся неуклюжими.

Этот ответ был скопирован с Другой вопрос которые не имеют такой же видимости, я тот же автор.

Теперь, когда выпущен JUnit 5, лучший вариант — использовать Assertions.assertThrows() (См Руководство пользователя Юнит 5).

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

public class FooTest {
  @Test
  public void doStuffThrowsIndexOutOfBoundsException() {
    Foo foo = new Foo();

    IndexOutOfBoundsException e = assertThrows(
        IndexOutOfBoundsException.class, foo::doStuff);

    assertThat(e).hasMessageThat().contains("woops!");
  }
}

Преимущества перед подходами в других ответах:

  1. Встроенный в JUnit
  2. Вы получаете полезное сообщение об исключении, если код в лямбда-выражении не генерирует исключение, и трассировку стека, если он генерирует другое исключение.
  3. Краткий
  4. Позволяет вашим тестам следовать Arrange-Act-Assert
  5. Вы можете точно указать, какой код вы ожидаете выдать исключение.
  6. Вам не нужно указывать ожидаемое исключение в throws пункт
  7. Вы можете использовать выбранную вами структуру утверждений, чтобы делать утверждения об обнаруженном исключении.

Аналогичный метод будет добавлен в org.junit Assert в JUnit 4.13.

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

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

  try {
    foo.doStuff();
  } catch (Throwable ex) {
    e = ex;
  }

  assertTrue(e instanceof IndexOutOfBoundsException);
}

БДД Стильное решение: Юнит 4 + Перехватить исключение + УтверждатьJ

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(foo).doStuff();

    then(caughtException()).isInstanceOf(IndexOutOfBoundsException.class);

}

Исходный код

Зависимости

eu.codearte.catch-exception:catch-exception:1.3.3

Используя УтверждатьJ утверждение, которое можно использовать вместе с JUnit:

import static org.assertj.core.api.Assertions.*;

@Test
public void testFooThrowsIndexOutOfBoundsException() {
  Foo foo = new Foo();

  assertThatThrownBy(() -> foo.doStuff())
        .isInstanceOf(IndexOutOfBoundsException.class);
}

Это лучше, чем @Test(expected=IndexOutOfBoundsException.class) потому что это гарантирует, что ожидаемая строка в тесте вызвала исключение, и позволяет вам проще проверить более подробную информацию об исключении, например сообщение:

assertThatThrownBy(() ->
       {
         throw new Exception("boom!");
       })
    .isInstanceOf(Exception.class)
    .hasMessageContaining("boom");

Инструкции Maven/Gradle здесь.

Чтобы решить ту же проблему, я создал небольшой проект:http://code.google.com/p/catch-Exception/

Используя этого маленького помощника, вы бы написали

verifyException(foo, IndexOutOfBoundsException.class).doStuff();

Это менее подробное правило, чем правило ExpectedException в JUnit 4.7.По сравнению с решением, предоставленным skaffman, вы можете указать, в какой строке кода вы ожидаете исключение.Надеюсь, это поможет.

Обновлять: В JUnit5 есть улучшение для тестирования исключений: assertThrows.

следующий пример взят из: Руководство пользователя Юнит 5

 @Test
void exceptionTesting() {
    Throwable exception = assertThrows(IllegalArgumentException.class, () -> 
    {
        throw new IllegalArgumentException("a message");
    });
    assertEquals("a message", exception.getMessage());
}

Оригинальный ответ с использованием JUnit 4.

Существует несколько способов проверить возникновение исключения.Я также обсудил приведенные ниже варианты в своем посте. Как писать отличные модульные тесты с помощью JUnit

Установить expected параметр @Test(expected = FileNotFoundException.class).

@Test(expected = FileNotFoundException.class) 
public void testReadFile() { 
    myClass.readFile("test.txt");
}

С использованием try catch

public void testReadFile() { 
    try {
        myClass.readFile("test.txt");
        fail("Expected a FileNotFoundException to be thrown");
    } catch (FileNotFoundException e) {
        assertThat(e.getMessage(), is("The file test.txt does not exist!"));
    }

}

Тестирование с ExpectedException Правило.

@Rule
public ExpectedException thrown = ExpectedException.none();

@Test
public void testReadFile() throws FileNotFoundException {

    thrown.expect(FileNotFoundException.class);
    thrown.expectMessage(startsWith("The file test.txt"));
    myClass.readFile("test.txt");
}

Подробнее о тестировании исключений можно прочитать в JUnit4 wiki для тестирования исключений и bad.robot — Правило JUnit в ожидании исключений.

Вы также можете сделать это:

@Test
public void testFooThrowsIndexOutOfBoundsException() {
    try {
        foo.doStuff();
        assert false;
    } catch (IndexOutOfBoundsException e) {
        assert true;
    }
}

ИМХО, лучший способ проверить наличие исключений в JUnit - это шаблон try/catch/fail/assert:

// this try block should be as small as possible,
// as you want to make sure you only catch exceptions from your code
try {
    sut.doThing();
    fail(); // fail if this does not throw any exception
} catch(MyException e) { // only catch the exception you expect,
                         // otherwise you may catch an exception for a dependency unexpectedly
    // a strong assertion on the message, 
    // in case the exception comes from anywhere an unexpected line of code,
    // especially important if your checking IllegalArgumentExceptions
    assertEquals("the message I get", e.getMessage()); 
}

А assertTrue может быть немного сильным для некоторых людей, поэтому assertThat(e.getMessage(), containsString("the message"); может быть предпочтительнее.

Решение JUnit 5

@Test
void testFooThrowsIndexOutOfBoundsException() {    
  Throwable exception = expectThrows( IndexOutOfBoundsException.class, foo::doStuff );

  assertEquals( "some message", exception.getMessage() );
}

Дополнительная информация о JUnit 5 на http://junit.org/junit5/docs/current/user-guide/#writing-tests-assertions

Я испробовал многие методы, представленные здесь, но они были либо сложны, либо не совсем соответствовали моим требованиям.На самом деле написать вспомогательный метод можно довольно просто:

public class ExceptionAssertions {
    public static void assertException(BlastContainer blastContainer ) {
        boolean caughtException = false;
        try {
            blastContainer.test();
        } catch( Exception e ) {
            caughtException = true;
        }
        if( !caughtException ) {
            throw new AssertionFailedError("exception expected to be thrown, but was not");
        }
    }
    public static interface BlastContainer {
        public void test() throws Exception;
    }
}

Используйте это следующим образом:

assertException(new BlastContainer() {
    @Override
    public void test() throws Exception {
        doSomethingThatShouldExceptHere();
    }
});

Нулевые зависимости:нет необходимости в мокито, нет необходимости в powermock;и отлично работает с финальными классами.

Самый гибкий и элегантный ответ для Junit 4, который я нашел в Блог Мкёнга.Он обладает гибкостью try/catch используя @Rule аннотация.Мне нравится этот подход, потому что вы можете прочитать определенные атрибуты настроенного исключения.

package com.mkyong;

import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;

public class Exception3Test {

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void testNameNotFoundException() throws NameNotFoundException {

        //test specific type of exception
        thrown.expect(NameNotFoundException.class);

        //test message
        thrown.expectMessage(is("Name is empty!"));

        //test detail
        thrown.expect(hasProperty("errCode"));  //make sure getters n setters are defined.
        thrown.expect(hasProperty("errCode", is(666)));

        CustomerService cust = new CustomerService();
        cust.findByName("");

    }

}

Решение Java 8

Если вам нужно решение, которое:

  • Использует лямбды Java 8.
  • Делает нет зависеть от любой магии JUnit
  • Позволяет проверять наличие нескольких исключений в рамках одного метода тестирования.
  • Проверяет, что исключение выдается определенным набором строк в вашем методе тестирования, а не какой-либо неизвестной строкой во всем методе тестирования.
  • Возвращает фактический объект исключения, который был создан, чтобы вы могли его дополнительно изучить.

Вот служебная функция, которую я написал:

public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
    try
    {
        runnable.run();
    }
    catch( Throwable throwable )
    {
        if( throwable instanceof AssertionError && throwable.getCause() != null )
            throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
        assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
        assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
        @SuppressWarnings( "unchecked" )
        T result = (T)throwable;
        return result;
    }
    assert false; //expected exception was not thrown.
    return null; //to keep the compiler happy.
}

(взято из моего блога)

Используйте его следующим образом:

@Test
public void testThrows()
{
    RuntimeException e = expectException( RuntimeException.class, () -> 
        {
            throw new RuntimeException( "fail!" );
        } );
    assert e.getMessage().equals( "fail!" );
}

JUnit имеет для этого встроенную поддержку с «ожидаемый» атрибут

В моем случае я всегда получаю RuntimeException от базы данных, но сообщения различаются.И исключение необходимо обрабатывать соответственно.Вот как я это тестировал:

@Test
public void testThrowsExceptionWhenWrongSku() {

    // Given
    String articleSimpleSku = "999-999";
    int amountOfTransactions = 1;
    Exception exception = null;

    // When
    try {
        createNInboundTransactionsForSku(amountOfTransactions, articleSimpleSku);
    } catch (RuntimeException e) {
        exception = e;
    }

    // Then
    shouldValidateThrowsExceptionWithMessage(exception, MESSAGE_NON_EXISTENT_SKU);
}

private void shouldValidateThrowsExceptionWithMessage(final Exception e, final String message) {
    assertNotNull(e);
    assertTrue(e.getMessage().contains(message));
}

Просто создайте Matcher, который можно будет включать и выключать, вот так:

public class ExceptionMatcher extends BaseMatcher<Throwable> {
    private boolean active = true;
    private Class<? extends Throwable> throwable;

    public ExceptionMatcher(Class<? extends Throwable> throwable) {
        this.throwable = throwable;
    }

    public void on() {
        this.active = true;
    }

    public void off() {
        this.active = false;
    }

    @Override
    public boolean matches(Object object) {
        return active && throwable.isAssignableFrom(object.getClass());
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("not the covered exception type");
    }
}

Чтобы использовать его:

добавлять public ExpectedException exception = ExpectedException.none();, затем:

ExceptionMatcher exMatch = new ExceptionMatcher(MyException.class);
exception.expect(exMatch);
someObject.somethingThatThrowsMyException();
exMatch.off();

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

@Rule
public ExpectedException exceptions = ExpectedException.none();


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

  1. Тип возникшего исключения
  2. Сообщение об исключении
  3. Причина исключения


public class MyTest {

    @Rule
    public ExpectedException exceptions = ExpectedException.none();

    ClassUnderTest classUnderTest;

    @Before
    public void setUp() throws Exception {
        classUnderTest = new ClassUnderTest();
    }

    @Test
    public void testAppleisSweetAndRed() throws Exception {

        exceptions.expect(Exception.class);
        exceptions.expectMessage("this is the exception message");
        exceptions.expectCause(Matchers.<Throwable>equalTo(exceptionCause));

        classUnderTest.methodUnderTest("param1", "param2");
    }

}

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

try{
   methodThatThrowMyException();
   Assert.fail("MyException is not thrown !");
} catch (final Exception exception) {
   // Verify if the thrown exception is instance of MyException, otherwise throws an assert failure
   assertTrue(exception instanceof MyException, "An exception other than MyException is thrown !");
   // In case of verifying the error message
   MyException myException = (MyException) exception;
   assertEquals("EXPECTED ERROR MESSAGE", myException.getMessage());
}

Дополнительно к чему НамШубПисатель сказал, убедитесь, что:

  • Экземпляр ExpectedException общественный (Связанный вопрос)
  • Ожидаемое исключение не созданный, скажем, методом @Before.Этот почта наглядно объясняет все тонкости порядка выполнения JUnit.

Делать нет сделай это:

@Rule    
public ExpectedException expectedException;

@Before
public void setup()
{
    expectedException = ExpectedException.none();
}

Окончательно, этот Сообщение в блоге ясно иллюстрирует, как утверждать, что выдано определенное исключение.

Я рекомендую библиотеку assertj-core для обработки исключения в тесте Junit

В Java 8 вот так:

//given

//when
Throwable throwable = catchThrowable(() -> anyService.anyMethod(object));

//then
AnyException anyException = (AnyException) throwable;
assertThat(anyException.getMessage()).isEqualTo("........");
assertThat(exception.getCode()).isEqualTo(".......);

Решение Junit4 с Java8 заключается в использовании этой функции:

public Throwable assertThrows(Class<? extends Throwable> expectedException, java.util.concurrent.Callable<?> funky) {
    try {
        funky.call();
    } catch (Throwable e) {
        if (expectedException.isInstance(e)) {
            return e;
        }
        throw new AssertionError(
                String.format("Expected [%s] to be thrown, but was [%s]", expectedException, e));
    }
    throw new AssertionError(
            String.format("Expected [%s] to be thrown, but nothing was thrown.", expectedException));
}

Тогда использование:

    assertThrows(ValidationException.class,
            () -> finalObject.checkSomething(null));

Обратите внимание, что единственным ограничением является использование final ссылка на объект в лямбда-выражении.Это решение позволяет продолжать тестовые утверждения вместо того, чтобы ожидать выполнения на уровне метода, используя @Test(expected = IndexOutOfBoundsException.class) решение.

Возьмем, к примеру, вы хотите написать Junit для приведенного ниже фрагмента кода.

public int divideByZeroDemo(int a,int b){

    return a/b;
}

public void exceptionWithMessage(String [] arr){

    throw new ArrayIndexOutOfBoundsException("Array is out of bound");
}

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

 @Rule
public ExpectedException exception=ExpectedException.none();

private Demo demo;
@Before
public void setup(){

    demo=new Demo();
}
@Test(expected=ArithmeticException.class)
public void testIfItThrowsAnyException() {

    demo.divideByZeroDemo(5, 0);

}

@Test
public void testExceptionWithMessage(){


    exception.expectMessage("Array is out of bound");
    exception.expect(ArrayIndexOutOfBoundsException.class);
    demo.exceptionWithMessage(new String[]{"This","is","a","demo"});
}

С помощью Java 8 вы можете создать метод, принимающий в качестве параметров код для проверки и ожидаемое исключение:

private void expectException(Runnable r, Class<?> clazz) { 
    try {
      r.run();
      fail("Expected: " + clazz.getSimpleName() + " but not thrown");
    } catch (Exception e) {
      if (!clazz.isInstance(e)) fail("Expected: " + clazz.getSimpleName() + " but " + e.getClass().getSimpleName() + " found", e);
    }
  }

а затем внутри вашего теста:

expectException(() -> list.sublist(0, 2).get(2), IndexOutOfBoundsException.class);

Преимущества:

  • не полагаясь ни на какую библиотеку
  • локализованная проверка — более точная и позволяет при необходимости иметь несколько подобных утверждений в одном тесте
  • легко использовать

Мое решение с использованием лямбда-выражений Java 8:

public static <T extends Throwable> T assertThrows(Class<T> expected, ThrowingRunnable action) throws Throwable {
    try {
        action.run();
        Assert.fail("Did not throw expected " + expected.getSimpleName());
        return null; // never actually
    } catch (Throwable actual) {
        if (!expected.isAssignableFrom(actual.getClass())) { // runtime '!(actual instanceof expected)'
            System.err.println("Threw " + actual.getClass().getSimpleName() 
                               + ", which is not a subtype of expected " 
                               + expected.getSimpleName());
            throw actual; // throw the unexpected Throwable for maximum transparency
        } else {
            return (T) actual; // return the expected Throwable for further examination
        }
    }
}

Вам необходимо определить FunctionalInterface, потому что Runnable не объявляет необходимое throws.

@FunctionalInterface
public interface ThrowingRunnable {
    void run() throws Throwable;
}

Метод можно использовать следующим образом:

class CustomException extends Exception {
    public final String message;
    public CustomException(final String message) { this.message = message;}
}
CustomException e = assertThrows(CustomException.class, () -> {
    throw new CustomException("Lorem Ipsum");
});
assertEquals("Lorem Ipsum", e.message);

Есть два способа написания тестового примера

  1. Аннотируйте тест с исключением, которое генерируется методом.Что-то вроде этого @Test(expected = IndexOutOfBoundsException.class)
  2. Вы можете просто перехватить исключение в тестовом классе, используя блок try catch, и утвердить сообщение, которое выдается методом в тестовом классе.

    try{
    }
    catch(exception to be thrown from method e)
    {
         assertEquals("message", e.getmessage());
    }
    

Я надеюсь, что это отвечает на ваш запрос счастливого обучения ...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top