Question

Je l'ai écrit quelques tests JUnit avec annotation @Test. Si ma méthode d'essai jette une exception vérifiée et si je veux faire valoir le message ainsi que l'exception, est-il un moyen de le faire avec l'annotation JUnit @Test? Autant que je sache, JUnit 4.7 ne fournit pas cette fonctionnalité, mais ne les versions futures de lui fournir? Je sais que dans .NET, vous pouvez affirmer le message et la classe d'exception. Vous recherchez une fonction similaire dans le monde Java.

Voici ce que je veux:

@Test (expected = RuntimeException.class, message = "Employee ID is null")
public void shouldThrowRuntimeExceptionWhenEmployeeIDisNull() {}
Était-ce utile?

La solution

Vous pouvez utiliser le @Rule annotation ExpectedException , comme ceci:

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

Notez que l'exemple dans les ExpectedException docs est (actuellement) mal -. Il n'y a pas de constructeur public, donc vous devez utiliser ExpectedException.none()

Autres conseils

J'aime la réponse @Rule . Cependant, si pour une raison quelconque, vous ne voulez pas utiliser des règles. Il y a une troisième option.

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

Avez-vous d'utiliser @Test(expected=SomeException.class)? Lorsque nous devons affirmer le message réel de l'exception, c'est ce que nous faisons.

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

Dans JUnit 4,13 (une fois libéré) vous pouvez faire:

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

Cela fonctionne aussi dans JUnit 5 mais avec différentes importations:

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

...

En fait, la meilleure utilisation est avec try / catch. Pourquoi? Parce que vous pouvez contrôler l'endroit où vous vous attendez à l'exception.

Prenons cet exemple:

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

Et si un jour le code est modifié et la préparation de test jeter un RuntimeException? Dans ce cas test réel est même pas testé et même si elle ne jette pas une exception passera le test.

Voilà pourquoi il est préférable d'utiliser try / catch que de compter sur l'annotation.

Raystorm avait une bonne réponse. Je ne suis pas un grand fan de règles non plus. Je fais quelque chose de similaire, sauf que je crée la classe utilitaire suivante pour améliorer la lisibilité et la facilité d'utilisation, ce qui est l'une des grandes plus'es des annotations en premier lieu.

Ajoutez cette classe utilitaire:

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

}

Ensuite, pour mon test unitaire, tout ce que je besoin est ce 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"
}

Si vous utilisez @Rule, l'ensemble d'exception est appliquée à toutes les méthodes d'essai dans la classe de test.

J'aime la réponse de user64141 mais a constaté qu'il pouvait être plus généralisée. Voici mon:

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

}

Notez que la déclaration laissant « échec » dans le bloc try provoque l'exception de l'affirmation liée à être pris; en utilisant le retour dans la déclaration de capture empêche.

Importer le catch-exception bibliothèque , et l'utiliser. Il est beaucoup plus propre que la règle de ExpectedException ou try-catch.

Exemple former les documents:

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
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top