wake-up-neo.com

Wie bestätige ich meine Ausnahmemeldung mit JUnit Test-Anmerkung?

Ich habe ein paar JUnit-Tests mit der @Test-Annotation geschrieben. Wenn meine Testmethode eine aktivierte Ausnahme auslöst und ich die Nachricht zusammen mit der Ausnahme bestätigen möchte, gibt es eine Möglichkeit, dies mit der Annotation JUnit @Test zu tun? AFAIK, JUnit 4.7 bietet diese Funktion nicht, aber werden sie in zukünftigen Versionen bereitgestellt? Ich kenne in .NET die Nachricht und die Ausnahmeklasse. Suchen Sie nach einer ähnlichen Funktion in der Java-Welt.

Das ist was ich will:

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

Sie können die Annotation @Rule mit ExpectedException wie folgt verwenden:

@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...
}

Beachten Sie, dass das Beispiel in den ExpectedException-Dokumenten (derzeit) falsch ist. Es gibt keinen öffentlichen Konstruktor. Daher müssen Sie ExpectedException.none() verwenden.

441
Jesse Merriman

Ich mag die @Rule Antwort. Wenn Sie jedoch aus irgendeinem Grund keine Regeln verwenden möchten. Es gibt eine dritte Möglichkeit.

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

Müssen Sie @Test(expected=SomeException.class) verwenden? Wenn wir die eigentliche Botschaft der Ausnahme bestätigen müssen, tun wir dies.

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

Eigentlich ist die Verwendung von try/catch am besten. Warum? Weil Sie den Ort steuern können, an dem Sie die Ausnahme erwarten.

Betrachten Sie dieses Beispiel:

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

Was passiert, wenn der Code eines Tages geändert wird und die Testvorbereitung eine RuntimeException auslöst? In diesem Fall wird der tatsächliche Test nicht einmal getestet und auch wenn er keine Ausnahme auslöst, wird der Test bestanden.

Daher ist es viel besser, try/catch zu verwenden, als sich auf die Annotation zu verlassen.

9
Krzysztof Cislo

Raystorm hatte eine gute Antwort. Ich bin auch kein großer Fan von Rules. Ich mache etwas Ähnliches, mit der Ausnahme, dass ich die folgende Dienstprogrammklasse erstellt, um die Lesbarkeit und Benutzerfreundlichkeit zu verbessern, was in erster Linie ein großer Pluspunkt von Anmerkungen ist. 

Fügen Sie diese Dienstprogrammklasse hinzu:

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

}

Dann brauche ich für meinen Gerätetest nur diesen Code:

@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"
}
7
user64141

In JUnit 4.13 (einmal veröffentlicht) können Sie Folgendes tun:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;

...

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

  assertEquals("a message", exception.getMessage());
}

Dies funktioniert auch in JUnit 5 aber mit unterschiedlichen Importen:

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

...
6
Johan Boberg

Bei Verwendung von @Rule wird der Ausnahmesatz auf alle Testmethoden in der Test-Klasse angewendet. 

2
Jyothi

Ich mag die Antwort von user64141, stellte aber fest, dass es allgemeiner sein könnte. Hier ist mein Take:

public abstract class ExpectedThrowableAsserter implements Runnable {

    private final Class<? extends Throwable> throwableClass;
    private final String expectedExceptionMessage;

    protected ExpectedThrowableAsserter(Class<? extends Throwable> throwableClass, String expectedExceptionMessage) {
        this.throwableClass = throwableClass;
        this.expectedExceptionMessage = expectedExceptionMessage;
    }

    public final void run() {
        try {
            expectException();
        } catch (Throwable e) {
            assertTrue(String.format("Caught unexpected %s", e.getClass().getSimpleName()), throwableClass.isInstance(e));
            assertEquals(String.format("%s caught, but unexpected message", throwableClass.getSimpleName()), expectedExceptionMessage, e.getMessage());
            return;
        }
        fail(String.format("Expected %s, but no exception was thrown.", throwableClass.getSimpleName()));
    }

    protected abstract void expectException();

}

Wenn Sie die "fail" -Anweisung im try-Block belassen, wird die zugehörige Assertionsausnahme abgefangen. Die Verwendung von return innerhalb der catch-Anweisung verhindert dies.

1
Addison Crump
@Test (expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "This is not allowed")
public void testInvalidValidation() throws Exception{
     //test code
}
0
aasha

Importieren Sie die Bibliothek " catch-exception " und verwenden Sie diese. Es ist viel sauberer als die ExpectedException-Regel oder ein try-catch.

Beispiel aus ihren Dokumenten:

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