JUnit 4 Тип ожидаемого исключения

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

public Pirate(String name, int initialGold) throws Exception {
    if(initialGold < 0)
        throw new Exception("Init Gold must be >= 0");
    this.name = name;
    this.numGold = initialGold;
    this.health = Pirate.DEFAULT_HEALTH;
    this.isCursed = false;
}

Мой фрагмент кода JUnit:

@Test
public static void constructorTest() throws Exception{
    rodgers = new Pirate("Dread Pirate Rodgers", 10000);
    assertEquals("Dread Pirate Rodgers" , rodgers.getName());
    assertEquals(10000, rodgers.getNumGold());
    assertEquals(100, rodgers.getHealth());
    assertEquals(false, rodgers.getIsCursed());
}

@Test()
public static void exceptionTest() throws Exception{
    rodgers = new Pirate("Dread Pirate Rodgers" , -100);

}

Я знаю, что мне нужно добавить ожидаемый = (некоторый тип исключения) в круглую скобку теста, но я не знаю, относится ли к типу исключения.

Ответ 1

На самом деле в JUnit 4.7 есть альтернатива @Test(expected=Xyz.class) с использованием Rule и ExpectedException

В вашем тестовом примере вы объявляете ExpectedException аннотацией @Rule и назначаете ему значение по умолчанию ExpectedException.none(). Затем в тесте, который ожидает исключение, вы заменяете значение фактическим ожидаемым значением. Преимущество этого состоит в том, что без использования уродливого метода try/catch вы можете дополнительно указать, каким было сообщение в исключении

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

@Test
public void myTest() {
    thrown.expect( Exception.class );
    thrown.expectMessage("Init Gold must be >= 0");

    rodgers = new Pirate("Dread Pirate Rodgers" , -100);
}

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

ДОБАВЛЕНИЕ Еще одним преимуществом использования ExpectedException является то, что вы можете более точно определить исключение в контексте тестового примера. Если в @Test(expected=Xyz.class) вы используете только @Test(expected=Xyz.class), то исключение Xyz может быть выброшено в любом месте кода теста, включая любые настройки теста или предварительные утверждения в методе теста. Это может привести к ложному срабатыванию.

Используя ExpectedException, вы можете отложить указание thrown.expect(Xyz.class) до тех пор, пока не будет выполнена какая-либо настройка и предварительные утверждения, непосредственно перед фактическим вызовом тестируемого метода. Таким образом, вы более точно определяете, какое исключение выдается фактическим вызовом метода, а не каким-либо из самих тестовых устройств.

JUnit 5 ПРИМЕЧАНИЕ:

JUnit 5 JUnit Jupiter полностью удалил @Test(expected=...), @Rule и ExpectedException. Они заменены на новый assertThrows(), который требует использования Java 8 и лямбда-синтаксиса. ExpectedException по-прежнему доступно для использования в JUnit 5 до JUnit Vintage. Также JUnit Jupiter также продолжит поддерживать исключение JUnit 4 ExpectedException посредством использования модуля junit-jupiter -igrationsupport, но только если вы добавите дополнительную аннотацию на уровне класса @EnableRuleMigrationSupport.

Ответ 2

Вы можете либо использовать ожидаемый в @Test аннотация или предоставить явный блок catch и выдать fail если поток программы не соответствует ожидаемому.

@Test(expected=Exception.class) // java.lang.Exception
public static void exceptionTest() throws Exception {
    rodgers = new Pirate("Dread Pirate Rodgers" , -100);
}

@Test
public static void exceptionTest() throws Exception {
    try {
        rodgers = new Pirate("Dread Pirate Rodgers" , -100);
        fail("should not reach this");
    } catch(Exception e) {
        // ok
    }
}

Мое личное предпочтение - это первое решение.

Ответ 3

Вы можете использовать JUnit 'expected' для проверки исключений:

@Test(expected = ExceptionYouWishToTestFor.class)  
public void divisionWithException() {  
    // Test Code
}

После этого вам нужно бросить это конкретное исключение в ваш код.

Ответ 4

Я бы не выбрал Exception, если золото не больше или равно нулю. Я бы выбрал IllegalArgumentException. Это, конечно, похоже на то, что ваш Pirate не имеет отрицательного количества золота.

public Pirate(String name, int initialGold) {
    if(initialGold < 0)
        throw new IllegalArgumentException("Init Gold must be >= 0");

Затем в вашем тестовом примере JUnit ожидаем IllegalArgumentException.

@Test(expected=IllegalArgumentException.class)
public static void exceptionTest() {