Как вы утверждаете, что в тестах JUnit 4 выбрасывается определенное исключение? - PullRequest
1834 голосов
/ 01 октября 2008

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

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

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

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

  assertTrue(thrown);
}

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

Ответы [ 33 ]

0 голосов
/ 04 октября 2017

Мое решение с использованием 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);
0 голосов
/ 01 октября 2017

В 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 голосов
/ 10 марта 2016

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

Я использовал assertTrue (логическое значение) в сочетании с try / catch для поиска ожидаемого исключения. Вот пример:

public void testConstructor() {
    boolean expectedExceptionThrown;
    try {
        // Call constructor with bad arguments
        double a = 1;
        double b = 2;
        double c = a + b; // In my example, this is an invalid option for c
        new Triangle(a, b, c);
        expectedExceptionThrown = false; // because it successfully constructed the object
    }
    catch(IllegalArgumentException e) {
        expectedExceptionThrown = true; // because I'm in this catch block
    }
    catch(Exception e) {
        expectedExceptionThrown = false; // because it threw an exception but not the one expected
    }
    assertTrue(expectedExceptionThrown);
}
...