web-dev-qa-db-fra.com

Android JUnit Testing ... Comment s'attendre à une exception

J'essaie d'écrire des tests en utilisant le framework de test intégré Android Junit. Je rencontre un problème avec un test dans lequel je m'attends à une exception. Dans JUnit, l'annotation pour la méthode de test serait: 

@Test(expected = ArithmeticException.class)

Cependant, sous Android, ce test échoue avec une exception ArithmeticException.

Je comprends que l’implémentation Android n’est qu’un sous-ensemble de JUnit 3 et n’autorise même pas l’annotation @Test (doit être @SmallTest, @MediumTest ou @LargeTest, et aucune de celles-ci ne permet le 'attendu = ..'. paramètre), mais cela semble être un test assez important, et il semblerait que le framework de test Android ferait sérieusement défaut s'il ne comportait pas cette fonctionnalité.

Remarque: J'ai testé cela en ajoutant le fichier JUnit au projet et en ajoutant les annotations à mes méthodes de test. Pour moi, il est logique que les annotations soient complètement ignorées car le framework Android (runner?) Ne recherche pas cette annotation et l'ignore simplement. Fondamentalement, je cherche simplement la «bonne» façon de procéder dans le cadre. 

42
Gimbl

L'idiome standard 3 pour ce type de test était:

public void testThatMethodThrowsException()
{
  try
  {
    doSomethingThatShouldThrow();
    Assert.fail("Should have thrown Arithmetic exception");
  }
  catch(ArithmeticException e)
  {
    //success
  }
}
59

Maintenant, JUnit4 est disponible via Android SDK (voir Android-test-kit )

Update : c'est officiel maintenant sur d.Android.com :

AndroidJUnitRunner est un nouveau programme d'exécution de test dégroupé pour Android, , Qui fait partie de la bibliothèque de tests du support Android. Il peut être téléchargé au format Via le référentiel de support Android. Le nouveau coureur contient Toutes les améliorations de GoogleInstrumentationTestRunner et ajoute plus de Fonctionnalités:

  • Support JUnit4
  • Registre d'instrumentation pour accéder aux arguments d'instrumentation, de contexte et d'ensembles
  • Filtres de test @SdkSupress et @RequiresDevice
  • Tester les délais
  • Eclatement des tests
  • Prise en charge de RunListener à intégrer au cycle de vie du test
  • Mécanisme de surveillance d'activité ActivityLifecycleMonitorRegistry

Donc, Style de test d'exception JUnit4 utilisant les annotations attendues:

@Test(expected= IndexOutOfBoundsException.class) 
public void empty() { 
     new ArrayList<Object>().get(0); 
}

ou des règles d'exception attendues:

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

@Test
public void shouldTestExceptionMessage() throws IndexOutOfBoundsException {
    List<Object> list = new ArrayList<Object>();

    thrown.expect(IndexOutOfBoundsException.class);
    thrown.expectMessage("Index: 0, Size: 0");
    list.get(0); // execution will never get past this line
}

est également possible.

Reportez-vous à documentation officielle pour plus de détails sur la configuration de la bibliothèque de support de test.

24
sandrstar

Je cherchais de bonnes solutions, mais aucune solution ne me satisfaisait vraiment. Alors, j'ai créé le mien.

public final void assertThrows(VoidFunction v, Class<? extends Exception> e) {
    try {
        v.call();
    } catch (Exception ex) {
        if (!ex.getClass().equals(e)) {
            Assert.fail();
        }
        // Do nothing, basically succeeds test if same exception was thrown.
        return;
    }

    // Fails if no exception is thrown by default.
    Assert.fail();
}

Où VoidFunction est une interface simple:

@FunctionalInterface
public interface VoidFunction {
    void call();
}

Ceci est utilisé comme suit (par exemple):

@Test
public void testFoo() {
    assertThrows(() -> foo.bar(null)), NullPointerException.class);
    assertThrows(() -> foo.setPositiveInt(-5)), IllegalArgumentException.class);
    assertThrows(() -> foo.getObjectAt(-100)), IndexOutOfBoundsException.class);
    assertThrows(new VoidFunction() {
            @Override
            public void call() {
                foo.getObjectAt(-100);
            }
        }, IndexOutOfBoundsException.class); // Success
    assertThrows(new VoidFunction() {
                @Override
                public void call() {
                    throw new Exception();
                }
            }, NullPointerException.class); // Fail

}

J’ai inclus un appel sans utiliser le lambda, ce qui facilite la compréhension du code parfois, du moins pour moi. Simple à utiliser et permettant de multiples captures d’exception avec la même méthode. 

1
Lurr