Pruebas de Android JUnit… Cómo esperar una excepción

4 minutos de lectura

avatar de usuario
Gimbl

Estoy intentando escribir algunas pruebas usando el marco de prueba integrado de Android Junit. Tengo un problema con una prueba en la que espero que se produzca una excepción. En JUnit, la anotación para el método de prueba sería:

@Test(expected = ArithmeticException.class)

Sin embargo, en Android, esta prueba falla con una ArithmeticException.

Entiendo que la implementación de Android es solo un subconjunto de JUnit 3, y ni siquiera permite la anotación @Test (debe ser @SmallTest, @MediumTest o @LargeTest, y ninguno de ellos permite el ‘expected=..’ parámetro), pero esto parece una prueba bastante significativa, y parece que el marco de prueba de Android faltaría seriamente si no tuviera esta función.

Nota : Probé esto agregando el jar JUnit al proyecto y agregando las anotaciones a mis métodos de prueba. Para mí, tiene sentido por qué las anotaciones se ignorarían por completo porque el marco de Android (¿corredor?) No está buscando esa anotación y simplemente la ignora. Básicamente, solo estoy buscando la forma “correcta” de hacer esto dentro del marco.

El modismo estándar de junit 3 para este tipo de prueba era:

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

  • Esta expresión también funciona en JUnit4 cuando desea verificar el estado de algo después de que se lanza la excepción. Realmente no puede afirmar nada cuando usa el idioma “esperado” después de que se lanza la excepción.

    – Soham

    16 mayo 2016 a las 21:57

  • Debes desmarcar esta respuesta como la correcta y marcar la de sandrstar, que es una mejor manera.

    – Seynorth

    16 de noviembre de 2020 a las 15:18

avatar de usuario
estrella de arena

Ahora JUnit4 está disponible a través de Android SDK (consulte kit de prueba de Android)

Actualizar: ya es oficial d.android.com:

AndroidJUnitRunner es un nuevo ejecutor de pruebas desagregado para Android, que forma parte de la biblioteca de pruebas de soporte de Android y se puede descargar a través del repositorio de soporte de Android. El nuevo corredor contiene todas las mejoras de GoogleInstrumentationTestRunner y agrega más funciones:

  • Soporte JUnit4
  • Registro de instrumentación para acceder a argumentos de instrumentación, contexto y paquete
  • Filtros de prueba @SdkSupress y @RequiresDevice
  • Tiempos de espera de prueba
  • fragmentación de pruebas
  • Compatibilidad con RunListener para conectarse al ciclo de vida de ejecución de prueba
  • Mecanismo de supervisión de actividad ActivityLifecycleMonitorRegistry

Asi que, Estilo JUnit4 de prueba de excepción usando la anotación esperada:

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

o reglas de excepción esperadas:

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

también es posible.

Referirse a documentación oficial para obtener más detalles sobre cómo configurar la biblioteca de soporte de prueba.

  • ¿Te funciona esto con las pruebas unitarias? es decir, en el directorio de prueba del proyecto en lugar del directorio androidTest?

    – Louth

    27 de abril de 2015 a las 8:49

  • @Louth sí, en realidad lo uso principalmente sin gradle y funciona bien la mayor parte del tiempo. No he probado eclipse, pero IntelliJ Idea está bien. Puede usar maven o simplemente obtener jar de su instalación SDK de Android (descomprima aar de extras\android\m2repository\com\android\support\test\testing-support-lib\0.1).

    – estrella de arena

    27 de abril de 2015 a las 23:12

  • Sí, saludos @sandrstar. Este es un hilo bastante antiguo y sí, usar Android Studio ahora es bastante sencillo. 🙂

    – Louth

    21/10/2015 a las 21:27

He estado buscando algunas buenas soluciones, sin embargo, ninguna de las soluciones fue realmente satisfactoria para mí. Entonces, creé el mío propio.

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

Donde VoidFunction es una interfaz simple:

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

Esto se usa de la siguiente manera (por ejemplo):

@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

}

Incluí una llamada sin usar la lambda, esto hace que a veces sea más fácil entender el código, al menos para mí. Fácil de usar y permite múltiples capturas de excepción en UN método.

¿Ha sido útil esta solución?