it-roy-ru.com

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

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

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

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

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

  assertTrue(thrown);
}

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

1838
SCdF

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

2214
skaffman

Правка Теперь, когда 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()

Смотрите эта статья для деталей

1251
NamshubWriter

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

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

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

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

447
daveb

Как уже говорилось ранее, в 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

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

203
Rafal Borowiec

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

  • для junit4.x используйте необязательный атрибут "ожидается" аннотации теста

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

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

110
walsh

; Т.Л. Dr

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

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

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

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

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

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

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

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

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

      @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) или Arrange Act 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. JUnit 4.13-beta-2 даже не поддерживает этот механизм:

    запрос на извлечение № 1519 : отменить ожидаемое исключение

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

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

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

    Как говорится в описании проекта, он позволяет кодировщику писать в беглой строке кода, перехватывающей исключение, и предлагает это исключение для последующего утверждения. И вы можете использовать любую библиотеку утверждений, например 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();
    

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

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

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

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

    Эти проблемы не будут применяться, если библиотека будет поддерживать лямбды, однако функциональность будет дублироваться набором инструментов 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, быстрый темп разработки и как де-факто тестовая зависимость - лучшее решение с JDK8 независимо от тестовой среды (JUnit или нет), предыдущие JDK вместо этого должны полагаться на try- catch блоки, даже если они кажутся неуклюжими.

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

96
Brice

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

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

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

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

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

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

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

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

50
NamshubWriter

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

public void testFooThrowsIndexOutOfBoundsException() {
  Throwable e = null;

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

  assertTrue(e instanceof IndexOutOfBoundsException);
}
40
Johan

BDD Решение стилей: JUnit 4 + Catch Exception + AssertJ

@Test
public void testFooThrowsIndexOutOfBoundsException() {

    when(foo).doStuff();

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

}

Исходный код

Зависимости

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

Используя утверждение 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 здесь.

33
weston

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

С помощью этого маленького помощника вы бы написали

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

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

32
rwitzel

Обновление: В 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

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

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

Использование trycatch

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 Rule .

29
Dilini Rajapaksha

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

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

ИМХО, лучший способ проверить наличие исключений в 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"); может быть предпочтительнее.

13
Alex Collins

Решение 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

12
Daniel Käfer

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

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; и отлично работает с выпускными классами.

11
Hugh Perkins

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

    }

}
10
Dherik

Решение 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!" );
}
9
Mike Nakis

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

8
Mark Bessey

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

@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));
}
7
Macchiatow

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

}
5
Jobin Joseph

Просто создайте 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();
5
Tor P

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

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

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

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

Не не сделать это:

@Rule    
public ExpectedException expectedException;

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

Наконец, в блоге this четко показано, как можно утверждать, что выбрасывается определенное исключение.

4
Bruce Wayne

Я рекомендую библиотеку 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(".......);
3
Piotr R

Решение 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).

2
Donatello

Взять, к примеру, вы хотите написать 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"});
}
1
Shirsh Sinha
    @Test(expectedException=IndexOutOfBoundsException.class) 
    public void  testFooThrowsIndexOutOfBoundsException() throws Exception {
         doThrow(IndexOutOfBoundsException.class).when(foo).doStuff();  
         try {
             foo.doStuff(); 
            } catch (IndexOutOfBoundsException e) {
                       assertEquals(IndexOutOfBoundsException .class, ex.getCause().getClass());
                      throw e;

               }

    }

Вот еще один способ проверить, правильно ли выброшено исключение или нет.

0
MangduYogii

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

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

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

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

0
Mohit ladia

С помощью 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);

Выгоды:

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

Мое решение с использованием 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);
0
heio