Domanda

Ho scritto un paio di test JUnit con @Test annotazione. Se il mio metodo di prova genera un'eccezione verificata e se voglio far valere il messaggio con l'eccezione, c'è un modo per farlo con JUnit @Test annotazioni? Per quanto ne so, JUnit 4.7 non fornisce questa funzionalità, ma non tutte le versioni future fornirle? So che in .NET si può affermare il messaggio e la classe di eccezione. Ricerca di funzionalità simile nel mondo Java.

Questo è quello che voglio:

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

Soluzione

È possibile utilizzare il @Rule annotazione con ExpectedException , in questo modo:

@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...
    System.out.println("=======Starting Exception process=======");
    throw new NullPointerException("Employee ID is null");
}

Si noti che l'esempio nella documentazione ExpectedException è (attualmente) sbagliato -. Non c'è costruttore pubblico, quindi bisogna usare ExpectedException.none()

Altri suggerimenti

Mi piace il @Rule risposta. Tuttavia, se per qualche motivo non si desidera utilizzare le regole. C'è una terza opzione.

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

Dovete usare @Test(expected=SomeException.class)? Quando dobbiamo affermare il messaggio vero e proprio dell'eccezione, questo è quello che facciamo.

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

In JUnit 4.13 (una volta rilasciato) si può fare:

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

Questo funziona anche in JUnit 5 ma con diverse importazioni:

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

...

In realtà, il miglior utilizzo è con try / catch. Perché? Poiché è possibile controllare il luogo dove ci si aspetta l'eccezione.

Si consideri questo esempio:

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

Che cosa se un giorno il codice viene modificato e la preparazione dei test lancerà una RuntimeException? In tal caso, prova effettiva non è ancora testato e anche se non genera alcuna eccezione il test passerà.

Questo è il motivo per cui è molto meglio usare try / catch che fare affidamento su l'annotazione.

RayStorm ha avuto una buona risposta. Io non sono un grande fan di regole sia. Faccio qualcosa di simile, solo che creo la seguente classe di utilità per aiutare la leggibilità e l'usabilità, che è uno dei grandi plus'es di annotazioni, in primo luogo.

Aggiungi questa classe di utilità:

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

}

Poi per il mio test di unità, ho solo bisogno di questo codice:

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

Se si utilizza @Rule, il set di eccezione si applica a tutti i metodi di test nella classe di test.

Mi piace la risposta di user64141 ma ho trovato che potrebbe essere più generalizzato. Ecco il mio prendere:

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

}

Si noti che lasciando il "fail" dichiarazione all'interno del blocco try causa l'eccezione asserzione correlate a essere catturati; utilizzando ritorno entro l'istruzione catch impedisce questo.

catch-eccezione biblioteca , e usare quella. 'Molto più pulita rispetto alla regola ExpectedException o un try-catch.

Esempio formare i loro documenti:

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()
  )
);
@Test (expectedExceptions = ValidationException.class, expectedExceptionsMessageRegExp = "This is not allowed")
public void testInvalidValidation() throws Exception{
     //test code
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top