Java Selenide - For-Looping Коллекция элементов с изменениями во время цикла - PullRequest
0 голосов
/ 02 апреля 2019

Фон

Я программирую на Java уже более 3 лет, но я впервые чувствую, что до сих пор не понимаю, как работает базовый цикл, о черт возьми!

Итак, у меня есть проект Selenide.Selenide - это веб-библиотека для автоматического тестирования, основанная на SeleniumHQ.

У меня есть простой цикл for, который просматривает список элементов изображения.


Настройка проекта

Зависимость:

compile group: 'com.codeborne', name: 'selenide', version: '5.2.2'

Импорт:

import static com.codeborne.selenide.Selenide.$$;
import static com.codeborne.selenide.Selectors.byXpath;

Код зла:

final ElementsCollection list = $$(byXpath("//img[@src='original src']"));
for (int i=0; i<list.size(); i++) {
    doSth(list.get(i));
}

Метод doSth:

void doSth(SelenideElement element) {
    Selenide.executeJavaScript("arguments[0].src = 'new src';", element);
}

Конечноприведенный выше код является простой версией кода, над которым я работаю, но структура ядра остается.


Проблема

Я считаю, что число циклов / итераций меньше ожидаемого,в моем случае это ожидаемое 4 против фактическое 2 .

1 Ответ

0 голосов
/ 02 апреля 2019

Анализ первопричин

Метод doSth пытается изменить атрибут src элемента img, который приходит из параметра. После изменения элемент img больше не будет выполнять XPath. Вопрос о том, соответствует ли элемент img XPath после модификации, имеет значение из-за того, как Selenide извлекает элементы.

Поскольку коллекция элементов, выбранная XPath от Selenide, лениво оценивается так же, как и отдельные объекты-элементы, каждый из элементов в коллекции хранит только индекс элемента и коллекцию XPath (это упоминается в JavaDoc Selenide). Когда атрибут src одного из элементов коллекции обновляется, он влияет на последующую итерацию цикла, вызывая уменьшение динамического размера коллекции.

После прочтения исходного кода класса ElementsCollection мы узнаем, что ElementsCollection - это AbstractList с переопределенными методами. Поскольку условие завершения в цикле Java for вычисляется на каждой итерации, переопределенный метод size() фактически возвращает меньшее число с уменьшением 1 после каждой итерации цикла.


Решение

Поскольку первый (индекс 0) элемент списка имеет измененный src, список будет уменьшаться до 1 после каждой итерации, элемент n+1 будет занимать позицию n й элемент. Я всегда могу получить первый (индекс 0) элемент, который фактически дает мне следующий элемент, так как предыдущий элемент больше не будет оставаться в динамическом списке.

  • 1-я итерация:
    • [0] = element A
    • [1] = element B
    • [2] = element C
    • [3] = element D
  • 2-я итерация:
    • [0] = element B
    • [1] = element C
    • [2] = element D

Изменить цикл следующим образом:

final ElementsCollection list = $$(byXpath("//img[@src='original src']"));
final int count = list.size(); // extract to evaluate once only
for (int i=0; i<count; i++) {
    doSth(list.get(0)); // change i to 0
}
...