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

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

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

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

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

  assertTrue(thrown);
}

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

30 ответов


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, Используйте необязательный "ожидаемый" атрибут test annonation

    @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 framework

    @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());
    }
    
  • так

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


tl; dr

  • pre-JDK8: я буду рекомендовать старый добрый try-catch блок.

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

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

история

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

но эти пути не так элегантны и не смешиваются хорошо читабельность мудрый С другими инструментами.

  1. на try-catch блок вы должны написать блок вокруг тестируемого поведения и написать утверждение в блоке catch, что может быть хорошо, но многие считают, что этот стиль прерывает поток чтения теста. Также вам нужно написать Assert.fail в конце try блок в противном случае тест может пропустить одну сторону утверждений;PMD, в FindBugs или эхолот выявит такие проблемы.

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

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

      @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 правило также является попыткой исправить предыдущие предостережения, но он чувствует себя немного неудобно использовать, поскольку он использует стиль ожидания,EasyMock пользователи очень хорошо знают этот стиль. Это может быть удобно для некоторых, но если вы следуете Развитие, Обусловленное Поведением (BDD) или Организовать Акт Assert (AAA) принципы 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.

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

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

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

    быстрый пример взят с домашней страницы:

    // 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. EDIT: кажется, проект готовит поддержку Java 8 Lambdas.

    в настоящее время эта библиотека имеет два недостатка :

    • на момент написания этой статьи следует отметить, что эта библиотека основана на Mockito 1.x как он создает макет тестируемого объекта за сценой. Как Mockito до сих пор не обновляется!--34-->эта библиотека не может работать с конечными классами или конечными методами. И даже если он был основан на mockito 2 в текущей версии, для этого потребуется объявить global mock maker (inline-mock-maker), то что может не то, что вы хотите, как это mockmaker разные недостатки, что обычный mockmaker.

    • для этого требуется еще одна тестовая зависимость.

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

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

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

    и образец теста с AssertJ :

    @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) AssertJпростота в использовании, обнаруживаемый API, быстрый темп развития и как de facto тестовая зависимость-лучшее решение с JDK8 независимо от тестовой структуры (JUnit или нет), предыдущие JDKs должны полагаться на try-catch блоки, даже если они чувствуют себя неуклюжим.

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


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

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}

BDD Стиль: JUnit 4 + Исключение Catch + AssertJ

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(foo).doStuff();

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

}

исходный код

зависимости

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

С помощью AssertJ утверждение, которое можно использовать вместе с 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 здесь.


теперь, когда JUnit 5 выпустила, лучший вариант-использовать Assertions.assertThrows() (см. the Junit 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. вы получаете полезное сообщение об исключении, если код в лямбде не бросьте исключение и stacktrace, если он бросает другое исключение
  3. Краткий
  4. позволяет вашим тестам следовать Arrange-Act-Assert
  5. вы можете точно указать, какой код вы ожидаете, чтобы бросить исключение
  6. вам не нужно перечислять ожидаемое исключение в throws п.
  7. вы можете использовать структуру утверждений по вашему выбору, Чтобы сделать утверждения о пойманном исключении

похожее метод будет добавлен в org.junit Assert в JUnit 4.13.


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

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

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

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


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

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

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

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

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

установить


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

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

IMHO, лучший способ проверить исключения в 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 on 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();
    }
});

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


JUnit имеет встроенную поддержку для этого, с "ожидается" атрибут


решение Java 8

если вы хотите решение, которое:

  • использует Java 8 lambdas
  • тут не зависит от любого JUnit magic
  • позволяет проверить наличие нескольких исключений в рамках одного метода тестирования
  • проверяет исключение, создаваемое определенным набором строк в вашем методе тестирования вместо любой неизвестной строки во всем методе тестирования
  • дает фактический объект исключения это было брошено так, что вы можете дополнительно изучить его

вот функция утилиты, которую я написал:

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!" );
}

в моем случае я всегда получаю 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));
}

в 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");
    }

}

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

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());
}

самый гибкий и элегантный ответ для Junit 4, который я нашел в блог Mkyoung. Он имеет гибкость 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("");

    }

}

дополнительно к чему NamShubWriter сказал, убедитесь, что:

  • экземпляр ExpectedException является общественные (Вопрос)
  • В ExpectedException не экземпляр, скажем, метода @Before. Это в должности ясно объясняет все тонкости порядка исполнения JUnit.

Do не этого:

@Rule    
public ExpectedException expectedException;

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

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


просто сделайте 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 для приведенного ниже фрагмента кода

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 lambdas:

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. аннотировать тест с исключением, которое вызывается методом. Что-то вроде этого!--1-->
  2. вы можете просто поймать исключение в тестовом классе, используя блок try catch и assert на сообщение, которое выбрасывается из метода в тестовом классе.

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

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


решение 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 ссылка на объект в лямбда-выражение. Это решение позволяет продолжить тестовые утверждения вместо ожидания thowable на уровне метода с помощью @Test(expected = IndexOutOfBoundsException.class) решение.


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

в java 8, например:

//given

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

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