Правильная конфигурация тестового фреймворка. С#

Добрый день!

Помогите, пожалуйста, с верной конфигурацией фреймворка. Речь идёт о помощнике для работы с веб таблицами. Есть код, который собирает данные с таблицы и складывает их в список для ускорения и удобства работы. Он вполне адекватно работает. Проблема в том, что он также ищет в ячейках веб элементы (ссылки, чекбоксы, поля ввода) и предопределяет набор действий для них (клик, ввод текста и т.д.) Сейчас фреймворк сконфигурирован так, что метод FindElements(By.TagName()) из метода GetControl() вызывается на каждой ячейке, для проверки последней на наличие в ней веб элементов. Это самая большая проблема, т.к. для динамических таблиц, как у меня в проекте, проверка каждой ячейки занимает 5-8 секунд, на строку из 6 колонок уходит 45-50 секунд, соответственно обработка таблицы с 10 строками занимает почти 10 минут. Возможно, есть советы, как можно переписать код, чтобы избавиться от просадки? Код:

public static void ReadTable(IWebElement table)
{
//Initialize the table
_tableDatacollections = new List <TableDatacollection>();

        //Get all the columns from the table
        var columns = table.FindElements(By.TagName("th"));

        //Get all the rows
        var rows = table.FindElements(By.TagName("tr"));
        
        //Create row index
        int rowIndex = 0;
        foreach (var row in rows)
        {
            int colIndex = 0;
            var colDatas = row.FindElements(By.TagName("td"));

            //Store data only if it has value in the row
            if (colDatas.Count != 0)
            {
                foreach (var colValue in colDatas)
                {
                    _tableDatacollections.Add(new TableDatacollection
                    {
                        RowNumber = rowIndex,
                        ColumnName = columns[colIndex].Text != "" ?
                                     columns[colIndex].Text : colIndex.ToString(),
                        ColumnValue = colValue.Text,
                        ColumnSpecialValues = GetControl(colValue)
                    });

                    //Move to next column
                    colIndex++;
                }
            }
            rowIndex++;
        }
    }

    private static ColumnSpecialValue GetControl(IWebElement columnValue)
    {
        ColumnSpecialValue columnSpecialValue = null;

        //Check if the control has specific tags like input/hyperlink etc
        if (columnValue.FindElements(By.TagName("a")).Count > 0)
        {
            columnSpecialValue = new ColumnSpecialValue
            {
                ElementCollection = columnValue.FindElements(By.TagName("a")),
                ControlType = "hyperlink"
            };
        }

        if (columnValue.FindElements(By.TagName("input")).Count > 0)
        {
            columnSpecialValue = new ColumnSpecialValue
            {
                ElementCollection = columnValue.FindElements(By.TagName("input")),
                ControlType = "input"
            };
        }
        return columnSpecialValue;
    }

    public class TableDatacollection
    {
        public int RowNumber { get; set; }
        public string ColumnName { get; set; }
        public string ColumnValue { get; set; }
        public ColumnSpecialValue ColumnSpecialValues { get; set; }
    }

    public class ColumnSpecialValue
    {
        public IEnumerable<IWebElement> ElementCollection { get; set; }
        public string ControlType { get; set; }
    }

Дальше идут методы для работы с полученной таблицей, они не существенны. Просадку дают именно два if’a в методе GetControl(). Буду рад любой идее.

Парсінг займає стільки часу оскільки в коді на кожну з клітинок робиться запит через FindElement/FindElements (відпопідно кожен раз на пошук елементів тратиться час: код-драйвер → драйвер-браузер і назад браузер-драйвер → драйвер-код). Оптимальніше було б знайти таблицю і стягнути весь її вміст один раз (пробуйте через GetAttribute(“outerHTML”) або щось нагугліть в цьому роді). Далі отриманий вміст розпарсіть через лібу HtmlAgilityPack (https://htmlagilitypack.codeplex.com/).

1 лайк

ImplicitlyWait>0?

Нет, задержки там нет.

Спасибо за подсказку! Сегодня попробую

А вы проверьте - не может findElements отрабатывать 8 секунд на контекстном поиске в <td/>, разве что у этой <td/> сотни или тысячи чайлдов.

  1. Проверте ImplicitlyWait везде по коду. findElements будет ждать каждый раз время, которое установлено в ImplicitlyWait. При частых вызовах это тупо залипания. Решение - ставить таймаут ImplicitlyWait в 0 перед findElements и потом возвращать обратно. Можно обернуть в кастомный врапер для findElements.

  2. Иногда помогает использовать JavaScript для ускорения загрузки данных, вот хорошая статья по поводу:
    ...как прочитать много данных с веб-страницы? • А хотите, я расскажу вам...

Мне стыдно. Там и правда оказалась задержка, в одном месте пропустил.

И действительно - проблема решилась. Но задержка стояла на проверке IsElementPresent и большинство тестов падают из-за того, что не успевает выполнится проверка. Всем большое спасибо за помощь, буду решать новую проблему

2 лайка

Стыдно не решать проблемы, а избегать их решения:)

Мне кажется, такой вариант isElementPresent лучше (Java):

  • во-первых, он не кидает исключение при отсутствии элемента, это позитивно сказывается на быстродействии если использовать RemoteWebDriver (grid).
  • во-вторых так лаконичней
  • в-третьих, у вас наверное ошибка в названии метода, потому что в такой реализации метод не проверяет что элемент present, так как элемент уже передается в него как параметр.
private boolean isElementPresent(By element) 
   {
        return driver.findElements(element).size() > 0;
    }