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

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

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

11.12.2008 09:39:45
Vadzim 23.07.2016 12:30:26
7 ОТВЕТОВ
РЕШЕНИЕ

Взгляните на параметризованные тесты в 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;
    }
}

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

101
14.09.2012 09:24:22
Спасибо! Метод JUnit 4 лучше, чем метод JUnit 3, приведенный в другом ответе, поскольку JUnit 3 сбивает с толку бегущего по тесту Eclipse, а с помощью метода JUnit 4 вы можете повторно выполнить тесты и т. Д. название для теста - оно показывает только [0], [1] и т. д.
Hans-Peter Störr 12.12.2008 16:21:33
@hstoerr, похоже, что это будет в следующем выпуске JUnit :-) github.com/KentBeck/junit/commit/…
rescdsk 13.04.2012 15:32:16
Как бы вы изменили это, если бы вы хотели, чтобы каждый прогон [с другой комбинацией данных] изменял имя тестового прогона? Т.е. файл Path1 будет проверен как: test1Path1, test2Path?
monksy 2.09.2012 07:52:59
^ Обновленная ссылка: github.com/junit-team/junit4/commit/…
Alexander Udalov 19.03.2018 17:02:53

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

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

3
11.12.2008 10:16:57

Юнит 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());
    }

}
27
11.12.2008 11:04:15

Если 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
===============================================
1
18.07.2014 20:07:12
Я не знаю о теориях, но параметризованные тесты в JUnit показаны отдельно в затмении, а не сгруппированы вместе.
Hans-Peter Störr 18.07.2014 06:30:29

Вы можете рассмотреть возможность использования библиотеки 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.

Основные отличия от стандартного бегунка JUnit Parametrised:

  • более явно - параметры находятся в параметрах метода тестирования, а не в полях класса
  • меньше кода - вам не нужен конструктор для настройки параметров
  • Вы можете смешивать параметризованные с непараметрическими методами в одном классе
  • параметры могут быть переданы в виде строки CSV или из класса поставщика параметров
  • у класса провайдера параметров может быть столько параметров, сколько вам нужно, чтобы вы могли группировать разные случаи
  • у вас может быть метод теста, который предоставляет параметры (больше нет внешних классов или статики)
  • вы можете увидеть фактические значения параметров в вашей IDE (в Parametrised JUnit это только последовательные числа параметров)
2
20.05.2015 21:09:28

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

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

0
8.04.2016 19:04:29

Junit 5 параметризованных тестов

Параметризованные тесты JUnit 5 поддерживают это, позволяя использовать метод в качестве источника данных :

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

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

JUnit 5 DynamicTests

JUnit 5 также поддерживает это посредством понятия a DynamicTest, которое должно быть сгенерировано в a @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

10
8.09.2018 17:26:10