Как утвердить мое сообщение об исключении с аннотацией JUnit Test?

Я написал несколько тестов JUnit с аннотацией @Test. Если мой тестовый метод выдает проверенное исключение и если я хочу утверждать это сообщение вместе с исключением, есть ли способ сделать это с помощью аннотации JUnit @Test? AFAIK, JUnit 4.7 не предоставляет эту функцию, но предоставляет ли ее какие-либо будущие версии? Я знаю, что в .NET вы можете утверждать сообщение и класс исключений. Поиск аналогичной функции в мире Java.

Это то, что я хочу:

@Test (expected = RuntimeException.class, message = "Employee ID is null")
public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() {}

Ответ 1

Вы можете использовать аннотацию @Rule с ExpectedException, например:

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

@Test
public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() throws Exception {
    expectedEx.expect(RuntimeException.class);
    expectedEx.expectMessage("Employee ID is null");
    // do something that should throw the exception...
}

Обратите внимание, что пример в документах ExpectedException (в настоящее время) неправильный - нет никакого открытого конструктора, поэтому вы должны использовать ExpectedException.none().

Ответ 2

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

@Test
public void myTestMethod()
{
  try
  {
    final Integer employeeId = null;
    new Employee(employeeId);
    fail("Should have thrown SomeException but did not!");
  }
  catch( final SomeException e )
  {
    final String msg = "Employee ID is null";
    assertEquals(msg, e.getMessage());
  }
}

Ответ 3

Мне нравится ответ @Rule. Однако, если по какой-то причине вы не хотите использовать правила. Существует третий вариант.

@Test (expected = RuntimeException.class)
public void myTestMethod()
{
   try
   {
      //Run exception throwing operation here
   }
   catch(RuntimeException re)
   {
      String message = "Employee ID is null";
      assertEquals(message, re.getMessage());
      throw re;
    }
    fail("Employee Id Null exception did not throw!");
  }

Ответ 4

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

Добавьте этот класс утилиты:

import org.junit.Assert;

public abstract class ExpectedRuntimeExceptionAsserter {

    private String expectedExceptionMessage;

    public ExpectedRuntimeExceptionAsserter(String expectedExceptionMessage) {
        this.expectedExceptionMessage = expectedExceptionMessage;
    }

    public final void run(){
        try{
            expectException();
            Assert.fail(String.format("Expected a RuntimeException '%s'", expectedExceptionMessage));
        } catch (RuntimeException e){
            Assert.assertEquals("RuntimeException caught, but unexpected message", expectedExceptionMessage, e.getMessage());
        }
    }

    protected abstract void expectException();

}

Тогда для моего unit test мне нужен только этот код:

@Test
public void verifyAnonymousUserCantAccessPrivilegedResourceTest(){
    new ExpectedRuntimeExceptionAsserter("anonymous user can't access privileged resource"){
        @Override
        protected void expectException() {
            throw new RuntimeException("anonymous user can't access privileged resource");
        }
    }.run(); //passes test; expected exception is caught, and this @Test returns normally as "Passed"
}

Ответ 5

На самом деле лучше всего использовать try/catch. Зачем? Потому что вы можете контролировать место, где вы ожидаете исключения.

Рассмотрим следующий пример:

@Test (expected = RuntimeException.class)
public void someTest() {
   // test preparation
   // actual test
}

Что делать, если в один прекрасный день код будет изменен, а подготовка теста вызовет исключение RuntimeException? В этом случае фактический тест даже не проверяется, и даже если он не даст никакого исключения, тест пройдет.

Вот почему гораздо лучше использовать try/catch, чем полагаться на аннотацию.

Ответ 6

При использовании @Rule набор исключений применяется ко всем методам тестирования в классе Test.

Ответ 7

Импортируйте библиотеку catch-exception и используйте ее. Он намного чище, чем правило ExpectedException или try-catch.

Пример формы их документов:

import static com.googlecode.catchexception.CatchException.*;
import static com.googlecode.catchexception.apis.CatchExceptionHamcrestMatchers.*;

// given: an empty list
List myList = new ArrayList();

// when: we try to get the first element of the list
catchException(myList).get(1);

// then: we expect an IndexOutOfBoundsException with message "Index: 1, Size: 0"
assertThat(caughtException(),
  allOf(
    instanceOf(IndexOutOfBoundsException.class),
    hasMessage("Index: 1, Size: 0"),
    hasNoCause()
  )
);