Статьи

Советы разработчикам: C # Selenium с основами MSTest

Selenium — отличный инструмент для тестирования вашего пользовательского интерфейса. В Интернете есть множество отличных учебников, которые я рекомендую вам просмотреть. В этой статье рассматриваются некоторые основные этапы установки и простой пример кода .NET Core 2.1.

Настройки браузера

  1. Допущения: Chrome / Firefox (64-разрядная версия) / IE11 / Edge (Win10 или выше).
  2. Большинство из этих настроек должны быть сделаны для IE11, поскольку современные браузеры делают это по умолчанию, или альтернатива обычно все еще работает.

    • Всегда открывайте всплывающие окна в новой вкладке.
    • Отключите блокировку всплывающих окон.
    • IE11: включить защищенный режим для всех зон безопасности.
    • Отключить сохранение пароля.
    • Когда будет предложено автозаполнение, нажмите «Нет».
    • Установите масштаб до 100%.
  3. Перезапустите браузеры.

Настройки Windows

  1. Отключите сохранение экрана входа в систему, пока вы сидите, наблюдая, как автоматические тесты запускают экранную заставку, которая не портит ваш тест.
  2. Перезагрузите компьютер.

Установите веб-драйверы

  1. IE 11.
  • 64-разрядная версия также должна работать, но некоторые консультанты, с которыми я работал, рекомендовали использовать 32-разрядную версию более 64-разрядную по состоянию на 12/2018.

    • Извлеките «IEDriverServer.exe» из архива в папку c: \ Selenium.WebDrivers
  • Microsoft Edge (EdgeHtml).

    • https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
    • Edge версии 18 или выше, затем выполните следующую команду в командной строке от имени администратора.

      • DISM.exe / Online / Add-Capability /CapabilityName:Microsoft.WebDriver~~~~0.0.1.0.
      • Версия Edge меньше 18, затем выполните следующие действия.
    • В разделе «Загрузки»> Microsoft Edge (EdgeHtml)> щелкните верхнюю версию.

      • Сохраните файл «MicrosoftWebDriver.exe» в папку c: \ Selenium.WebDrivers.
  • Microsoft Edge (хром).

    1. Так как эта версия находится в Preview, я не загружал и не тестировал, но вот шаги.
    2. https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
    3. В разделе «Загрузки»> Microsoft Edge (Chromium)> для получения верхней версии нажмите x64.
    4. Извлеките «msedgedriver.exe» из архива в папку c: \ Selenium.WebDrivers.
  • Хром.

    1. https://sites.google.com/a/chromium.org/chromedriver/
    2. В разделе «Все версии, доступные для загрузки» рядом с «Последним стабильным выпуском» нажмите ссылку ChromeDriver> Нажмите «chromedriver_win32.zip».
    3. Извлеките «chromedriver.exe» из архива в папку c: \ Selenium.WebDrivers.
  • Fire Fox.

    1. https://github.com/mozilla/geckodriver/releases
    2. Под последним выпуском v #. ##. # В разделе «Активы» щелкните geckodriver — * — win64.zip.
    3. Извлеките «geckodriver.exe» из архива в папку c: \ Selenium.WebDrivers.
  • Создать приложение

    Полный исходный код находится по  адресу https://github.com/penblade/Tips/tree/master/Tips.Selenium .

    1. Создайте новый проект> MSTest Test Project (.NET Core).
    2. Установите следующие пакеты NuGet.

      • WaitHelpers от SeleniumExtras.WaitHelpers (версия 3.11.0).

        • Используется для проверок StalenessOf.
      • Поддержка Selenium Committers (v3.141.0).
      • WebDriver от Selenium Committers (версия 3.141.0).

    SRC / Test / Утилиты / BrowserType.cs

    namespace OpenQA.Selenium
    {
        public enum BrowserType
        {
            NotSet,
            Chrome,
            Firefox,
            Edge,
            IE11
        }
    }

    WebDriverFactory

    Создайте фабрику, чтобы получить правильный веб-драйвер браузера.

    using System;
    using OpenQA.Selenium.Chrome;
    using OpenQA.Selenium.Edge;
    using OpenQA.Selenium.Firefox;
    using OpenQA.Selenium.IE;
    namespace OpenQA.Selenium
    {
        internal static class WebDriverFactory
        {
            public static IWebDriver Create(BrowserType browserType, string seleniumWebDriversPath)
            {
                switch (browserType)
                {
                    case BrowserType.Chrome:
                        return new ChromeDriver(seleniumWebDriversPath);
                    case BrowserType.Firefox:
                        return new FirefoxDriver(seleniumWebDriversPath);
                    case BrowserType.Edge:
                        // Edge 18 or greater is installed via command line.  See docs for more info.
                        return new EdgeDriver();
                    case BrowserType.IE11:
                        return new InternetExplorerDriver(seleniumWebDriversPath);
                    default:
                        throw new ArgumentOutOfRangeException(nameof(browserType), browserType, null);
                }
            }
        }
    }

    WebDriverExtensions

    Я трудился над решением, хочу ли я создавать объекты класса против методов расширения  IWebDriver. Пройдя туда-сюда несколько раз, я остановился на методах расширения. После некоторых дальнейших исследований я решил придерживаться  соглашения об именах,  не включающего «I» перед классом расширений. Я решил сохранить код в  OpenQA.Selenium пространстве имен, за исключением фактического тестового класса, чтобы разработчикам не пришлось добавлять другой путь использования.

    using System;
    using System.Diagnostics;
    using OpenQA.Selenium.Support.UI;
    using ExpectedConditions = SeleniumExtras.WaitHelpers.ExpectedConditions;
    namespace OpenQA.Selenium
    {
        internal static class WebDriverExtensions
        {
            // Consider storing the DefaultWaitTime in the web.config.
            private const int DefaultWaitTime = 10;
            // Create a default wait time span so we can reuse the most common time span.
            private static readonly TimeSpan DefaultWaitTimeSpan = TimeSpan.FromSeconds(DefaultWaitTime);
            public static IWait<IWebDriver> Wait(this IWebDriver driver) => Wait(driver, DefaultWaitTimeSpan);
            public static IWait<IWebDriver> Wait(this IWebDriver driver, int waitTime) => Wait(driver, TimeSpan.FromSeconds(waitTime));
            public static IWait<IWebDriver> Wait(this IWebDriver driver, TimeSpan waitTimeSpan) => new WebDriverWait(driver, waitTimeSpan);
            public static IWebElement WaitUntilFindElement(this IWebDriver driver, By locator)
            {
                driver.Wait().Until(condition => ExpectedConditions.ElementIsVisible(locator));
                return driver.FindElement(locator);
            }
            public static IWebElement WaitUntilFindElement(this IWebDriver driver, By locator, Func<IWebDriver, IWebElement> condition)
            {
                driver.Wait().Until(condition);
                return driver.FindElement(locator);
            }
            public static IWebElement WaitUntilInitialPageLoad(this IWebDriver driver, string titleOnNewPage)
            {
                driver.Wait().Until(ExpectedConditions.TitleIs(titleOnNewPage));
                return driver.WaitUntilFindElementForPageLoadCheck();
            }
            public static IWebElement WaitUntilPageLoad(this IWebDriver driver, string titleOnNewPage, IWebElement elementOnOldPage)
            {
                // Inspiration:
                // http://www.obeythetestinggoat.com/how-to-get-selenium-to-wait-for-page-load-after-a-click.html
                // https://stackoverflow.com/questions/49866334/c-sharp-selenium-expectedconditions-is-obsolete
                driver.Wait().Until(ExpectedConditions.StalenessOf(elementOnOldPage));
                driver.Wait().Until(ExpectedConditions.TitleIs(titleOnNewPage));
                return driver.WaitUntilFindElementForPageLoadCheck();
            }
            private static IWebElement WaitUntilFindElementForPageLoadCheck(this IWebDriver driver) => driver.WaitUntilFindElement(By.XPath("html"));
            public static void ScrollIntoView(this IWebDriver driver, IWebElement element)
            {
                // Assumes IWebDriver can be cast as IJavaScriptExecuter.
                ScrollIntoView((IJavaScriptExecutor) driver, element);
            }
            private static void ScrollIntoView(IJavaScriptExecutor driver, IWebElement element)
            {
                // The MoveToElement does not scroll the element to the top of the page.
                //new Actions(driver).MoveToElement(session).Perform();
                driver.ExecuteScript("arguments[0].scrollIntoView(true);", element);
            }
            public static void Quit(this IWebDriver driver, BrowserType browserType)
            {
                driver.Quit();
                if (browserType != BrowserType.IE11) return;
                EndProcessTree("IEDriverServer.exe");
                EndProcessTree("iexplore.exe");
            }
            private static void EndProcessTree(string imageName)
            {
                // Inspiration
                // https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/taskkill
                // https://stackoverflow.com/questions/5901679/kill-process-tree-programmatically-in-c-sharp
                // https://stackoverflow.com/questions/36729512/internet-explorer-11-does-not-close-after-selenium-test
                // /f - force process to terminate
                // /fi <Filter> - /fi \"pid gt 0 \" - select all processes
                // /im <ImageName> - select only processes with this image name
                Process.Start(new ProcessStartInfo
                {
                    FileName = "taskkill",
                    Arguments = $"/f /fi \"pid gt 0\" /im {imageName}",
                    CreateNoWindow = true,
                    UseShellExecute = false
                })?.WaitForExit();
            }
        }
    }

    WebDriverTest

    Теперь, когда расширения настроены, давайте добавим наш тест. Мы откроем веб-страницу, перейдем по ссылке, дождемся загрузки страницы и перейдем к элементу.

    Для теста я хочу просмотреть список браузеров как часть одного и того же шага, чтобы убедиться, что я правильно настроил среду. Как только вы начнете добавлять тесты через конвейер, вы захотите изучить использование тестового прогона и указать браузер для тестирования во время выполнения с помощью файла конфигурации.

    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using OpenQA.Selenium;
    namespace Tips.Selenium.Test
    {
        [TestClass]
        public class WebDriverTest
        {
            private const string SeleniumWebDriversPath = @"C:\Selenium.WebDrivers";
            private const string TestUrl = @"https://dogfoodcon.com/";
            [TestMethod]
            [DataRow(BrowserType.Chrome, SeleniumWebDriversPath)]
            [DataRow(BrowserType.Firefox, SeleniumWebDriversPath)]
            [DataRow(BrowserType.Edge, SeleniumWebDriversPath)]
            [DataRow(BrowserType.IE11, SeleniumWebDriversPath)]
            public void VerifyRemoteWebDriversAreSetup(BrowserType browserType, string seleniumWebDriversPath)
            {
                using (var driver = WebDriverFactory.Create(browserType, seleniumWebDriversPath))
                {
                    driver.Navigate().GoToUrl(TestUrl);
                    // DogFoodCon
                    var pageLoadCheck = driver.WaitUntilInitialPageLoad("DogFoodCon");
                    var sessionsLink = driver.WaitUntilFindElement(By.XPath("//a[@title='Sessions']"));
                    sessionsLink.Click();
                    // Sessions - DogFoodCon
                    pageLoadCheck = driver.WaitUntilPageLoad("Sessions – DogFoodCon", pageLoadCheck);
                    var session = driver.WaitUntilFindElement(By.XPath("//a[text()='Jeff McKenzie']"));
                    // Scroll to the element, but don't verify it is visible to the user.
                    // I did this step just so you can see the session appear on the screen.
                    driver.ScrollIntoView(session);
                    driver.Quit(browserType);
                }
            }
        }
    }

    Ресурсы

    1. Полный исходный код находится в  https://github.com/penblade/Tips/tree/master/Tips.Selenium
    2. Введение в Selenium Webdriver с C # в Visual Studio 2015
    3. Миграция проекта Selenium из .NET Framework в .NET Core
    4. Наиболее полная шпаргалка Selenium WebDriver C #
    5. Вот несколько дополнительных  примечаний  по паре вопросов, с которыми я столкнулся при настройке потенциальных решений.

      • Мой Win10 Chrome продолжал отображать сообщение Защитника Windows.
      • Вы должны добавить свой путь к драйверу Selenium в переменную окружения% PATH%, но я достиг максимального ограничения символов.

    Вывод

    Я предоставил основы, необходимые для настройки Selenium, включая среду для Win10 и браузеры. Пример кода демонстрирует, как реализовать обычные вызовы для обработки ожиданий, поиска элементов и ожидания загрузки страницы в качестве методов расширения из IWebDriver для улучшения и оптимизации процесса. Следующим шагом будет изучение моделей Page Object.