Prueba JUnit con número dinámico de pruebas

95

En nuestro proyecto tengo varias pruebas de JUnit que, por ejemplo, toman cada archivo de un directorio y ejecutan una prueba en él. Si implemento un testEveryFileInDirectorymétodo en el, TestCaseesto aparece como solo una prueba que puede fallar o tener éxito. Pero estoy interesado en los resultados de cada archivo individual. ¿Cómo puedo escribir un TestCase/ TestSuitetal que cada archivo aparezca como una prueba separada, por ejemplo, en el TestRunner gráfico de Eclipse? (Codificar un método de prueba explícito para cada archivo no es una opción).

Compare también la pregunta ParameterizedTest con un nombre en Eclipse Testrunner .

Hans-Peter Störr
fuente
1
Véase también stackoverflow.com/questions/3257080/…
Vadzim

Respuestas:

102

Eche un vistazo a las pruebas parametrizadas en JUnit 4.

De hecho, hice esto hace unos días. Trataré de explicar ...

Primero construya su clase de prueba normalmente, ya que solo estaba probando con un archivo de entrada. Decora tu clase con:

@RunWith(Parameterized.class)

Cree un constructor que tome la entrada que cambiará en cada llamada de prueba (en este caso, puede ser el archivo en sí)

Luego, cree un método estático que devolverá una serie Collectionde matrices. Cada matriz de la colección contendrá los argumentos de entrada para el constructor de su clase, por ejemplo, el archivo. Decora este método con:

@Parameters

Aquí hay una clase de muestra.

@RunWith(Parameterized.class)
public class ParameterizedTest {

    private File file;

    public ParameterizedTest(File file) {
        this.file = file;
    }

    @Test
    public void test1() throws Exception {  }

    @Test
    public void test2() throws Exception {  }

    @Parameters
    public static Collection<Object[]> data() {
        // load the files as you want
        Object[] fileArg1 = new Object[] { new File("path1") };
        Object[] fileArg2 = new Object[] { new File("path2") };

        Collection<Object[]> data = new ArrayList<Object[]>();
        data.add(fileArg1);
        data.add(fileArg2);
        return data;
    }
}

También mira este ejemplo

bruno conde
fuente
1
¡Gracias! El método JUnit 4 es mejor que el método JUnit 3 dado en otra respuesta, ya que el JUnit 3 confunde al corredor de prueba de eclipse y con el método JUnit 4 puede volver a ejecutar las pruebas, etc. Solo me pregunto cómo puedo hacer que eclipse muestre un nombre de la prueba: solo muestra [0], [1], etc.
Hans-Peter Störr
@hstoerr, parece que esto estará en la próxima versión de JUnit :-) github.com/KentBeck/junit/commit/…
rescdsk
¿Cómo transformaría esto si quisiera que cada ejecución [con una combinación de datos diferente] modificara el nombre de la ejecución de la prueba? [Es decir, el archivo Path1 se probaría como: test1Path1, test2Path?
monksy
^ Enlace actualizado: github.com/junit-team/junit4/commit/…
Alexander Udalov
27

JUnit 3

public class XTest extends TestCase {

    public File file;

    public XTest(File file) {
        super(file.toString());
        this.file = file;
    }

    public void testX() {
        fail("Failed: " + file);
    }

}

public class XTestSuite extends TestSuite {

    public static Test suite() {
        TestSuite suite = new TestSuite("XTestSuite");
        File[] files = new File(".").listFiles();
        for (File file : files) {
            suite.addTest(new XTest(file));
        }
        return suite;
    }

}

JUnit 4

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class TestY {

    @Parameters
    public static Collection<Object[]> getFiles() {
        Collection<Object[]> params = new ArrayList<Object[]>();
        for (File f : new File(".").listFiles()) {
            Object[] arr = new Object[] { f };
            params.add(arr);
        }
        return params;
    }

    private File file;

    public TestY(File file) {
        this.file = file;
    }

    @Test
    public void testY() {
        fail(file.toString());
    }

}
McDowell
fuente
11

Pruebas parametrizadas Junit 5

Las pruebas parametrizadas de JUnit 5 respaldan esto al permitir el uso de un método como fuente de datos :

@ParameterizedTest
@MethodSource("fileProvider")
void testFile(File f) {
    // Your test comes here
}

static Stream<File> fileProvider() {
    return Arrays.asList(new File(".").list()).stream();
}

Pruebas dinámicas JUnit 5

JUnit 5 también apoya esto a través de la noción de a DynamicTest, que se generará en a @TestFactory, mediante el método estático dynamicTest.

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;

import java.util.stream.Stream;

@TestFactory
public Stream<DynamicTest> testFiles() {
    return Arrays.asList(new File(".").list())
            .stream()
            .map((file) -> dynamicTest(
                    "Test for file: " + file,
                    () -> { /* Your test comes here */ }));
}

Las pruebas ejecutadas en su IDE (IntelliJ aquí) se mostrarán así:

Salida en IntelliJ

avandeursen
fuente
3

Debería ser posible en JUnit 3 heredando TestSuitey anulando el tests()método para listar los archivos y para cada retorno una instancia de una subclase de TestCaseque toma el nombre del archivo como parámetro del constructor y tiene un método de prueba que prueba el archivo dado en el constructor.

En JUnit 4 podría ser incluso más fácil.

Michael Borgwardt
fuente
2

Podría considerar usar la biblioteca JUnitParams , por lo que tendría algunas opciones más (más limpias):

@org.junit.runner.RunWith(junitparams.JUnitParamsRunner.class)
public class ParameterizedTest {

    @org.junit.Test
    @junitparams.Parameters(method = "data")
    public void test1(File file) throws Exception {  }

    @org.junit.Test
    @junitparams.Parameters(method = "data")
    public void test2(File file) throws Exception {  }

    public static File[] data() {
        return new File[] { new File("path1"), new File("path2") };
    }
}

@org.junit.runner.RunWith(junitparams.JUnitParamsRunner.class)
public class ParameterizedTest {

    @org.junit.Test
    @junitparams.Parameters(value = { "path1", "path2" })
    public void test1(String path) throws Exception {
        File file = new File(path);
    }

    @org.junit.Test
    @junitparams.Parameters(value = { "path1", "path2" })
    public void test2(String path) throws Exception {
        File file = new File(path);
    }
}

Puede ver más ejemplos de uso aquí .

Además de JUnitParams, por qué escribir pruebas parametrizadas con él es más fácil y legible :

El proyecto JUnitParams agrega un nuevo corredor a JUnit y proporciona pruebas parametrizadas mucho más fáciles y legibles para JUnit> = 4.6.

Principales diferencias con el corredor parametrizado estándar JUnit:

  • más explícito: los parámetros están en los parámetros del método de prueba, no en los campos de clase
  • menos código: no necesita un constructor para configurar los parámetros
  • puede mezclar métodos parametrizados con métodos no parametrizados en una clase
  • params se puede pasar como una cadena CSV o desde una clase de proveedor de parámetros
  • La clase de proveedor de parámetros puede tener tantos parámetros proporcionando métodos como desee, de modo que pueda agrupar diferentes casos.
  • puede tener un método de prueba que proporcione parámetros (ya no hay clases externas o estática)
  • puede ver los valores reales de los parámetros en su IDE (en JUnit's Parametrised son solo números consecutivos de parámetros)
falsarella
fuente
1

Si TestNG es una opción, puede usar Parámetros con DataProviders .

La prueba de cada archivo individual tendrá su resultado mostrado en el informe basado en texto o en la interfaz de usuario del complemento TestNG de Eclipse. El número total de pruebas ejecutadas contará cada uno de sus archivos individualmente.

Este comportamiento difiere de las teorías JUnit , en las que todos los resultados se agrupan bajo una entrada de "teoría" y solo cuentan como 1 prueba. Si desea informes de resultados separados en JUnit, puede probar Pruebas parametrizadas .

Prueba y entradas

public class FileTest {

    @DataProvider(name="files")
    public File[][] getFiles(){
        return new File[][] {
            { new File("file1") },
            { new File("file2") }
        };
        // or scan a directory
    }

    @Test(dataProvider="files")
    public void testFile(File file){
        //run tests on file
    }
}

Salida de ejemplo

PASSED: testFile(file1)
PASSED: testFile(file2)

===============================================
    Default test
    Tests run: 2, Failures: 0, Skips: 0
===============================================
Ben Hutchison
fuente
No conozco teorías, pero las pruebas parametrizadas en JUnit se muestran por separado en eclipse, no agrupadas.
Hans-Peter Störr