Тест JUnit с динамическим числом тестов

В нашем проекте у меня есть несколько JUnit тестов, например. взять каждый файл из каталога и запустить на нем тест. Если я реализую метод testEveryFileInDirectory в TestCase, это отображается как только один тест, который может потерпеть неудачу или преуспеть. Но меня интересуют результаты по каждому отдельному файлу. Как я могу написать TestCase/TestSuite, чтобы каждый файл отображался как отдельный тест, например. в графическом TestRunner of Eclipse? (Кодирование явного метода теста для каждого файла не является вариантом.)

Сравните также вопрос ParameterizedTest с именем в Eclipse Testrunner.

Ответ 1

Взгляните на Параметрированные тесты в JUnit 4.

На самом деле я сделал это несколько дней назад. Я попытаюсь объяснить...

Сначала создайте свой тестовый класс, как обычно, с помощью одного входного файла. Украсьте свой класс:

@RunWith(Parameterized.class)

Постройте один конструктор, который принимает входные данные, которые будут меняться при каждом тестовом вызове (в этом случае это может быть сам файл)

Затем создайте статический метод, который вернет Collection массивов. Каждый массив в коллекции будет содержать входные аргументы для вашего конструктора классов, например. файл. Украсьте этот метод:

@Parameters

Здесь образец класса.

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

Также проверьте этот пример

Ответ 2

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

}

Ответ 3

JUnit 5

JUnit 5 поддерживает это через понятие DynamicTest, которое должно быть сгенерировано в @TestFactory, посредством статический метод 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 */ }));
}

Тесты, запущенные в вашей среде IDE (IntelliJ здесь), будут отображаться следующим образом:

Вывод в IntelliJ

Ответ 4

Должно быть возможно в JUnit 3 путем наследования от TestSuite и переопределения метода tests() для перечисления файлов и для каждого возврата экземпляр подкласса TestCase, который принимает имя файла как параметр конструктора и имеет тест метод, который проверяет файл, указанный в конструкторе.

В JUnit 4 это может быть еще проще.

Ответ 5

Вы можете рассмотреть возможность использования библиотеки JUnitParams, поэтому у вас есть еще несколько (более чистых) опций:

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

Вы можете увидеть более примеры использования здесь.

Кроме того, о JUnitParams, почему списание параметризованных тестов с ним проще и читабельнее:

Проект JUnitParams добавляет нового участника в JUnit и обеспечивает много более простые и читаемые параметризованные тесты для JUnit >= 4.6.

Основные отличия от стандартного JNnit Parametrised runner:

  • более явный - параметры находятся в параметрах метода тестирования, а не в полях класса
  • less code - вам не нужен конструктор для настройки параметров
  • вы можете смешивать параметризованные с непараметризованными методами в одном классе
  • params могут передаваться как строка CSV или из класса поставщика параметров
  • класс поставщика параметров может иметь столько параметров, которые предоставляют методы, как вы хотите, чтобы вы могли группировать разные случаи.
  • у вас может быть метод тестирования, который предоставляет параметры (без внешних классов или статики)
  • вы можете видеть фактические значения параметров в вашей среде IDE (в JUnit Parametrised это только последовательные числа параметров)

Ответ 6

Если TestNG является опцией, вы можете использовать Параметры с DataProviders.

Каждый отдельный тестовый файл будет иметь результат, указанный в текстовом отчете или в интерфейсе Eclipse TestNG. Количество запущенных тестов будет считать каждый из ваших файлов индивидуально.

Это поведение отличается от JUnit Theories, в котором все результаты сосредоточены под одной "теоретической" записью и считаются только 1 тестом. Если вам нужна отдельная отчетность о результатах в JUnit, вы можете попробовать Параметрированные тесты.

Тест и входы

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

Пример вывода

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

===============================================
    Default test
    Tests run: 2, Failures: 0, Skips: 0
===============================================

Ответ 7

У меня была аналогичная проблема, и я написал простой JUnit 4 runner, который позволяет меди динамически генерировать тесты.

https://github.com/kimble/junit-test-factory