Удаленка для jenkins+selenide+selenoid+allure+docker спецов на 2-3 часа в день. 100% remote! Присоединиться к проекту

Тестовый метод с многочисленным перебором комбинаций атрибутов

dataprovider
java
selenium
webdriver
Теги: #<Tag:0x00007fedbff7f508> #<Tag:0x00007fedbff7f2b0> #<Tag:0x00007fedbff7f0f8> #<Tag:0x00007fedbff7ee50>

(Paul Manuilenko) #1

Доброго времени суток, уважаемые форумчане!

Подскажите как поступить в случае, когда нужно перебрать все ноды коллекций, которые передаются атрибутами в тестовый метод? Нужно что бы каждый вариант сравнился с каждым (можно со всем и с собой же).

Пример:

@Test(enabled = true)
    public void translation() {
        translator.openThePage();
        exp = translator.translate("langFrom", "LangTo", "lineFromFile");
        assertEquale(translator.GetTextFromTheResultBox(), exp);
    }

Нужно передать в langFrom String локали, к примеру “en”, “fr” и т.д.
Так же нужно поступить и с LangTo.
lineFromFile - это число строки из файла с переводимыми фразами, тоже для каждой пары языков меняется, к примеру от 0 до 5.

Моя единственная идея:
Применить @DataProvider (можно только к одному из атрибутов метода).
К примеру можно завернуть в цикл и инкрементировать lineFromFile.
Но это не явно и усложнит фикс упавшего теста.

Но даже в таком случае, придется делать отдельные тест для каждого языка, к примеру:

  1. Тест перевода с английского, передать туда “перевод на…” при помощи DataProvider и завернуть в цикл, где инкрементировать lineFromFile.
  2. Тест перевода с французкого, передать туда “перевод на…” при помощи DataProvider и завернуть в цикл, где инкрементировать lineFromFile.
    И так далее.

30 языков = 30 тестов с вложенным циклом и передачей туда 30ти target-языков при помощи DataProvider.

Меня смущает такое решение, может кто-то предложить, что-то лучше?


(Sergey Korol) #2

Ну если нужно действительно все перевести (без повторяющихся языков), то можно сделать следующим образом:

    @DataSupplier(flatMap = true)
    public StreamEx getLangData() {
        val languages = asList("ru", "en", "fr", "de");
        val amountOfLines = 5;

        return IntStreamEx.rangeClosed(0, amountOfLines).flatMapToObj(i ->
                StreamEx.of(languages)
                        .cross(languages)
                        .filterKeyValue((k, v) -> !k.equals(v))
                        .map(pair -> Tuple.of(i, pair.getKey(), pair.getValue())));
    }


    @Test(dataProvider = "getLangData")
    public void shouldTranslateSpecifiedLine(final int line, final String from, final String to) {
        log.info("Translating line #{} from {} to {}", line, from, to);
    }

Достаточно подключить test-data-supplier библиотеку. В примере выше также задействованы streamex, vavr и lombok.


(Paul Manuilenko) #3

Благодарю!
Хотелось бы решение проще, с минимальным применением сторонних библиотека / фреймворков…


(Sergey Korol) #4

Вам достаточно подключить только одну - test-data-supplier. Все остальное подтянется транзитивно. Библиотеки я перечислил лишь для того, чтобы можно было проанализировать синтаксис.

Хочется изобрести свой велосипед с cross product на стримах? You’re welcome. :slight_smile: Будет ли это проще? Нет. Можно конечно без стримов, старыми добрыми вложенными циклами сделать. А потом еще распихивать все по двумерным массивам стандартного data provider. Но кто на это захочет тратить свое время?


(Александр Ефимов) #5

Если нет желания подключать сторонние решения, то можно сделать все на чистой джаве:

@Test(dataProvider = "getLangData")
    public void shouldTranslateSpecifiedLine(TranslateData data) {
        log.info("Translating line #{} from {} to {}",  data.line, data.from, data.to);
    }

    @DataProvider
    public Object[][] getLangData() {
        List<String> languages = asList("ru", "en", "fr", "de");
        int amountOfLines = 5;
        List<TranslateData> testData = new ArrayList<>();
        IntStream.range(0, amountOfLines)
                .forEach(i -> languages.forEach(left -> languages.stream()
                        .filter(right -> !left.equals(right))
                        .forEach(right -> testData.add(new TranslateData(i, left, right)))));

        return toObjectArray(testData);
    }

    private <T> Object[][] toObjectArray(List<T> list) {
        Object[][] returnValue = new Object[list.size()][1];
        int index = 0;
        for (Object[] each : returnValue) {
            each[0] = list.get(index++);
        }
        return returnValue;
    }
    private class TranslateData {
        private int line;
        private String from;
        private String to;

        TranslateData(int line, String from, String to) {
            this.line = line;
            this.from = from;
            this.to = to;
        }
    }