Могут ли методы расширения использовать нестатические поля?

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

У меня есть набор тестов, реализованный с помощью Selenium/C#/NUnit.

Раньше я использовал PageFactory для определения элементов моей страницы. PageFactory устарел, поэтому было логично переключиться на определение моих элементов как IWebElements:

Домашняя страница.cs...

IWebElement UsernameTextBox = driver.FindElement(By.Id("username"));
IWebElement PasswordTextBox = driver.FindElement(By.Id("password"));
IWebElement LoginButton = driver.FindElement(By.Id("login"));

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

Чтобы решить эту проблему, я изменил тип элементов на By:

Домашняя страница.cs...

By UsernameTextBox = By.Id("username");
By PasswordTextBox = By.Id("password");
By LoginButton = By.Id("login");

Это позволяет мне определять элементы, а затем запрашивать DOM в нужное время. Отлично, проблема решена. Только теперь у меня другая проблема. Мне понравилась возможность связывать методы с IWebElements для удобства чтения:

LoginButton.Click();

Но тип 'By' не содержит методов, которые есть у IWebElement. Итак, следующий логический шаг: создайте метод расширения.

public static class ByExtensionMethods {
    public static void Click(this By elementLocator) {
        driver.FindElement(elementLocator);
    }
}

Отлично, проблема решена. Только теперь у меня другая проблема. Мой набор тестов не может использовать статический IWebDriver, потому что я хочу выполнять свои тесты параллельно. К сожалению, метод расширения требует, чтобы драйвер был статическим.

Поэтому, если я не смогу каким-то образом использовать свой нестатический IWebDriver внутри метода расширения, похоже, я не могу достичь своей цели по цепочке методов из элементов "By"...


person Zuno    schedule 31.01.2020    source источник
comment
Вы можете передать драйвер в качестве параметра метода щелчка, который позволит вам сделать LoginButton.Click(driver);   -  person DavidG    schedule 31.01.2020


Ответы (3)


Могут ли методы расширения использовать нестатические поля?

No.

Поэтому, если я не смогу каким-то образом использовать свой нестатический IWebDriver внутри метода расширения, похоже, я не могу достичь своей цели по цепочке методов из элементов "By"...

Просто передайте свой объект драйвера методу расширения и используйте его.

Пример:

public static class ByExtensionMethods {
    public static void Click(this By elementLocator, IWebDriver driver) {
        driver.FindElement(elementLocator);
    }
}
person Alexbogs    schedule 31.01.2020

Мне также пришлось найти замену Page Factory. К счастью, в C# есть удобная функция под названием Члены выражения.

В случае вашей домашней страницы элементами будут:

IWebElement UsernameTextBox => driver.FindElement(By.Id("username"));
IWebElement PasswordTextBox => driver.FindElement(By.Id("password"));
IWebElement LoginButton => driver.FindElement(By.Id("login"));

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

person Jonah    schedule 31.01.2020
comment
И обязательно обратите внимание, что члены с телом выражения — это просто более красивый способ определения свойств. - person Greg Burghardt; 06.02.2020

Я также отвечаю на это, чтобы расширить уже данные ответы (я упомянул методы цепочки вне типа «По»).

Итак, чтобы сделать это, я обнаружил, что мне следует сделать так, чтобы методы расширения имели тип «По» и возвращали ту же самую ссылку, которую я использовал...

    public static By Click(this By elementLocator, IWebDriver driver) 
    {
        driver.FindElement(elementLocator).Click();
        return elementLocator;
    }

    public static By Click2(this By elementLocator, IWebDriver driver) 
    {
        driver.FindElement(elementLocator).Click();
        return elementLocator;
    }

Это позволяет мне сделать следующее:

            HomePage homePage = new HomePage(_driver);

            homePage
            .PrivacyPolicyLink
            .Click(_driver)
            .Click2(_driver);

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

person Zuno    schedule 03.02.2020
comment
Чего вы действительно пытаетесь достичь? Использование элементов с телом выражения прекрасно заменяет Фабрику страниц. Обертывание By кажется излишним. - person Jonah; 03.02.2020
comment
На ваш вопрос есть два ответа. 1) Один из моих коллег говорит, что он по-прежнему генерирует исключение для него при использовании методов с телом выражения, но я посмотрю, что на самом деле происходит, потому что, если вы говорите, что это должно работать, возможно, происходит что-то еще. 2) Причина, по которой я упаковываю By, заключается в том, что у меня есть другой класс, который использует делегат для первой проверки интерактивности элемента, затем прокручивает его, а затем выполняет фактическое действие. Я не упомянул об этом, потому что предоставленное решение позволяет мне вызывать этот код. - person Zuno; 03.02.2020