Pruebas dinámicas con JUnit

Publicado el Saturday 17 de October de 2009. | 3 comentarios
Categoría: Programación y diseño | Tags: ,

JUnit es un sistema para realizar pruebas unitarias que cuando te acostumbras a utilizarlo, se convierte en una herramienta indispensable. La mayoría de las veces (casi siempre), el método de trabajo es el mismo: se crea la clase de pruebas con los métodos a probar y ya está.

Pero ¿qué pasa si queremos hacer pruebas unitarias creadas dinámicamente en función de datos externos? Es decir, no tenemos las clase de test A con sus métodos y la clase B con sus métodos, etc. si no que tenemos una sola clase, la cual queremos reutilizar una y otra vez como si fueran test distintos basándonos en datos distintos. Por ejemplo, hacer una prueba determinada como tantos ficheros haya en un carpeta X. La prueba consiste en algo tan tonto como validar que el fichero en cuestion contenga la letra “z”, en caso de que no la tenga, fallará.

Una solución pobre sería hacer una única clase de prueba con un método donde nos recorremos todos los ficheros a testear y realizamos la prueba pertinente en cada de ellos con sus assert o fails. .

Solución mala

import junit.framework.TestCase;
import java.io.File;

public class BadTest extends TestCase {

    public void testFiles() {
        File[] files = new File("/var/tmp").listFiles();
        System.out.println("Probando "+ files.length);
        for (File file : files) {
            System.out.println("Probando "+ file.getName());
            assertTrue(file.getName().contains("z"));
        }
    }
}

El problema de la solución mala es que si falla un fichero, toda la prueba finaliza y se dejan de validar los siguientes ficheros (y podemos tener miles y fallar en el primero), así que la prueba no vale.

Para este caso, lo ideal sería poder ejecutar una prueba distinta e independiente, basada en la misma clase de test, por cada uno de estos ficheros. Pero ¿cómo haríamos esto? Para hacerlo debemos crear primero una suite. Una suite no es más que una clase cualquiera (no tiene porqué heredar de ninguna otra clase de JUnit) que implementa el método estático suite(), retornando un instancia de la clase TestSuite de JUnit. Dentro de este método, es responsabilidad nuestra crear una nueva instancia de dicha clase y añadir las clases de test con el método addTest(). Y para hacer tantas pruebas como ficheros, lo que hacemos es crear una clase anónima que hereda de TestCase. Durante su creación, le pasamos el fichero a probar como parámetro final. A continuación, una prueba que si funciona.

Solución buena

import junit.framework.TestCase;
import junit.framework.TestSuite;

import java.io.File;
import java.io.IOException;

public class DinamicSuite {

    public static TestSuite suite() throws IOException {

        TestSuite suite = new TestSuite();

        for (File file : new File("/var/tmp").listFiles()) {

            suite.addTest(createDinamicTest(file, "Validando "+file.getName()));
        }

        return suite;
    }

    private static TestCase createDinamicTest(final File file, String name) {
        TestCase test = new TestCase() {
            public void runTest() throws Throwable {
                assertTrue(file.getName().contains("z"));
            }
        };
        test.setName(name);
        return test;
    }

}

Bastante sencillo y elegante, ¿no crees?

Popularity: 1% [?]

3 Responses to “Pruebas dinámicas con JUnit”

  1. jerocles says:

    Muy interesante tu post sobre los test dinamicos… ¿pero podrías dar
    otro ejemplo?
    En este caso en tu test no estas probando código, que es el objetivo
    habitual de los test…
    Tu estás probando que cierto juego de datos está bien… el único
    código es el propio de validar los datos :)

    Si quisieras validar datos estaría muy bien el ejemplo, solo te
    pregunto por un caso de uso en el que exista un test dinámico que
    pruebe código

  2. No suelo trabajar con suites de test. En junit 4, al trabajar con anotaciones y tener varias configuraciones de ejecución puedes decidir ejecutarlos todos, algunos o ningunos. En cualquier caso buen ejemplo de como probar las fixtures (mi manera snob y bárbara de llamar a los juegos de datos a los que se refiere Jeroclo)

  3. Akbarr says:

    Yo me he encontrado casos como esos muchas veces, y lo hacía de una forma muy parecida a la que has puesto. Básicamente la clase que yo hacía extendía TestCase, y luego tenía un método suite como el tuyo, donde abría el fichero y creaba las instancias de la propia clase, normalmente leyendo la configuración de cada test de un XML y rellenando las propiedades de cada objeto de test por reflection.

    La mayor diferencia con lo que propones tú es que la clase “grande” ya es la clase de test, que normalmente es la que tiene el código gordo, evitando la incomodidad de tener que crear una clase anónima con mucho código. Pero vamos, que la idea es exastamente la misma.

Leave a Reply