NET5 — Как запустить множество веб-приемочных тестов на одной машине

Допустим, я хочу запустить так называемые приемочные веб-тесты на современной (на момент вопроса) машине, которая, скажем, обычно имеет где-то между < strong>16 и 128 логических ядер. Число может быть разным в каждом конкретном случае, но давайте пока ограничимся этим диапазоном.

Под приемочным веб-тестом я подразумеваю тест, который открывает веб-страницу в одном из браузеров (Chrome/FireFox/Edge/... ) с помощью < strong>драйвер (например, chromedriver / geckodriver и т. д.), манипулирует веб-страницей так, как хочет тест, а затем собирает некоторые выходные данные (например, есть ли на веб-странице этот или тот элемент ИЛИ переход к этому или эту ожидаемую страницу). Фактические детали не имеют значения.

Учитывая, что такие тесты, естественно, тратят большую часть времени на ожидание (чтобы быть уверенным, что, когда они хотят манипулировать какой-либо веб-страницей [элементом], она точно загружена), тогда кажется разумным предположим, что если у меня есть N логических ядер на машине, то я должен иметь возможность создать как минимум N таких веб-приемочных тестов.

Типичный код C# для этого можно резюмировать следующим образом:

namespace WebAcceptanceTests
{
    public static class Chrome
    {
        public static async Task Run(
            Uri uri, 
            Func<ChromeDriver, Task> manipulate, 
            Action<ChromeDriver> validate)
        {
            var chromeDriverService = ChromeDriverService.CreateDefaultService();
            chromeDriverService.HideCommandPromptWindow = true;
            var options = new ChromeOptions();

            // To make Chrome window invisible.
            options.AddArgument("--headless");
            using var driver = new ChromeDriver(chromeDriverService, options);

            try
            {
                driver.Manage().Window.Maximize();
                driver.Navigate().GoToUrl(uri);

                await manipulate(driver);
                validate(driver);
            }
            finally
            {
                driver.Quit();
            }
        }
    }
}

где manipulate выполняет некоторые манипуляции со страницей (например, пытается нажать некоторые кнопки / вводит какой-либо текст / и т. д.), а validate выполняет некоторую проверку (например, если manipulate ввел имя пользователя и пароль, а затем нажал кнопку входа, то действительно ли сайт перешел на страницу авторизации). Фактические детали того, что делают эти manipulate и validate, не имеют значения. Однако manipulate — это длительный процесс, потому что сайту нужно загрузить страницу и выполнить некоторую работу здесь или там. Следовательно, мы можем смоделировать это с помощью метода, который просто ждет и ничего не делает, например:

        public static async Task Manipulate(ChromeDriver driver)
        {
            // Do some useful stuff here instead of just waiting.
            await Task.Delay(60_000);
        }

Однако, если я начну создавать такие драйверы, то очень быстро (когда будет создано менее 10 драйверов) некоторые из созданных драйверов начнут выдавать странные ошибки, такие как: OpenQA.Selenium.WebDriverException : The HTTP request to the remote WebDriver server for URL http://localhost:52382/session timed out after 60 seconds.

Компьютер тестового сервера, на котором я получаю эти ошибки, имеет 16 ядер и достаточно оперативной памяти, чтобы без проблем открывать сотни вкладок Chrome, но небольшое количество драйверов Chrome (менее 10), похоже, не работает параллельно.

Есть ли у кого-нибудь идеи, как заставить работать несколько хромированных драйверов параллельно? В идеале я бы хотел открыть драйверы (в 3-4 раза больше ядер), потому что они в основном будут ждать и ничего не делать.

Спасибо.


person Konstantin Konstantinov    schedule 30.01.2021    source источник
comment
Непонятно, как именно вы запускаете тесты. Но, чтобы дать вам какое-то направление, вам нужно использовать какой-то пул ваших потоков, чтобы гарантировать, что вы не лишите машину ресурсов. Вот пример в Powershell, который запускает тесты в параллельных максимум X процессах за раз. Ключевые вещи, на которые следует обратить внимание, это Get-Job и Start-Job.   -  person NightOwl888    schedule 31.01.2021
comment
C#/.NET просто не подходит для запуска автоматических тестов на основе браузера. Вся экосистема веб-разработчиков перешла на использование таких инструментов, как Cypress и Mocha, которые управляют безголовыми экземплярами Chrome, работающими либо локально, либо на ферме.   -  person Dai    schedule 03.02.2021
comment
Вероятно, дубликат этого гораздо более сжато сформулированного вопроса: start-t" title="сколько максимальное количество одновременных потоков соединений Chrome я могу запустить t"> stackoverflow.com/questions/52220159/   -  person Ian Mercer    schedule 03.02.2021
comment
@IanMercer Я согласен, что это в основном квалифицируется как дублирующий вопрос. За исключением того, что ответ не был принят, а комментарии намекают, что вы можете запускать несколько браузеров, что и делает приведенный выше код. Пожалуйста, обратите внимание, что эти http://localhost:52382/session различны для каждого драйвера, и похоже, что ответ [еще не принят] в приведенной выше ссылке неприменим.   -  person Konstantin Konstantinov    schedule 04.02.2021
comment
C# отлично подходит для параллельного запуска любого количества тестов без каких-либо проблем. На самом деле мы проводим тест против развертывания Selenoid.   -  person AlfeG    schedule 24.02.2021


Ответы (1)


Мы достигаем этого, используя параллельный запуск NUnit, параккекузабке с помощью фикстуры.

Выделите драйвер во время OneTimeSetup. Делайте все, что нужно для теста, в одном приспособлении. В OneTimeTearDown удалите драйвер. Мы делаем это в базовом классе, от которого наследуются все фикстуры веб-приемочных тестов.

    [Parallelizable(ParallelScope.Fixtures)]
    public abstract class WebDriverTest
    {
        protected IDriver driver;

        [OneTimeSetup]
        public void PrepareDriver()
        {
            // ...
            this.driver = new ChromeDriver(chromeDriverService, options);
            // ...
        }

        [OneTimeTearDown]
        public void CleanupDriver()
        {
            this.driver.Dispose();
        }

        [TearDown]
        public void ScreenshotForFailedTest()
        {
            var testStatus = GetTestStatus();

            if (!string.IsNullOrEmpty(testStatus) && testStatus.Equals("Failed"))
            {
                this.driver.TakeScreenshot(); // extension method with a take screenshot functionality
                // log more details if needed
            }
        }
    }

[OneTimeTearDown] выполняется, даже если есть неудачные тесты

В качестве бонуса берем скрин

Используя этот фрагмент кода, мы запускаем около 500 дымовых тестов для хрома по 5-6 минут на каждый коммит.

person AlfeG    schedule 24.02.2021