С#, расширяющий класс Selenium Webdriver

Я хотел бы добавить свойство статической строки, которое будет отслеживать имя текущего теста. Я решил, что лучший способ сделать это — использовать WebDriver, поскольку это единственный объект, который переносится во все объекты моей страницы.

Есть ли способ расширить класс WebDriver, чтобы добавить строковое свойство, которое я могу установить?

РЕДАКТИРОВАТЬ: поскольку WebDriver использует интерфейс IWebDriver, возможно, я бы расширил интерфейс?

РЕДАКТИРОВАТЬ № 2: Добавление примера того, что мне сейчас нужно для загрузки моего WebDriver:

protected static NLog.Logger _logger = LogManager.GetCurrentClassLogger();
protected static IWebDriver _driver;

/// <summary>
/// Spins up an instance of FireFox webdriver which controls the browser using a
/// FireFox plugin using a stripped down FireFox Profile.
/// </summary>
protected static void LoadDriver()
{
    ChromeOptions options = new ChromeOptions();
    try
    {
        var profile = new FirefoxProfile();
        profile.SetPreference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream doc xls pdf txt");

        _driver = new FirefoxDriver(profile);
        _driver.Navigate().GoToUrl("http://portal.test-web01.lbmx.com/login?redirect=%2f");
    }
    catch(Exception e)
    {
        Console.WriteLine(e.Message);
        throw;
    }
}

person Milo    schedule 15.08.2016    source источник
comment
Можете ли вы привести пример?   -  person Florent B.    schedule 15.08.2016
comment
Добавлен пример того, что мне сейчас нужно для загрузки WebDriver. Это внутри абстрактного класса, который заботится о настройке/очистке/использовании тестов.   -  person Milo    schedule 15.08.2016
comment
почему бы не инициализировать статическую строку в вашей функции выполнения?   -  person Leon Barkan    schedule 15.08.2016
comment
@LeonBarkan Класс является абстрактным со статическими методами для выполнения. Я не верю, что можно установить строку, которую я могу изменить для каждого другого теста. Если я ошибаюсь, покажите пример.   -  person Milo    schedule 15.08.2016


Ответы (4)


Вам нужно будет обернуть WebDriver, используя шаблон проектирования «Декоратор».

public class MyWebDriver : IWebDriver
{
    private IWebDriver webDriver;
    public string CurrentTest { get; set; }

    public MyWebDriver(IWebDriver webDriver)
    {
        this.webDriver = webDriver
    }

    public Method1()
    {
        webDriver.Method1();
    }

    public Method2()
    {
        webDriver.Method2();
    }

    ...
}

А затем передайте любой драйвер, который вы используете в данный момент.

var profile = new FirefoxProfile();
MyWebDriver driver = new MyWebDriver(new FirefoxDriver(profile));

Таким образом, вы делегируете интерфейсные методы IWebDriver FirefoxDriver, но можете добавлять любые подходящие дополнения.

person Nick Spicer    schedule 15.08.2016
comment
Спасибо. Это похоже на то, что предложил @LeonBarkan, но это кажется наиболее правильной реализацией. Я начал реализовывать его и сообщу, если я заработаю. - person Milo; 15.08.2016
comment
Я пытаюсь реализовать это, и Intellisense заставила меня реализовать все методы IWebDriver с 'throw new NotImplementedException()' в качестве их тел. Как в большинстве случаев использовать версию метода IWebDriver по умолчанию? Например, метод FindElement: public IWebElement FindElement(By by) { throw new NotImplementedException(); } - person Milo; 15.08.2016
comment
вам не нужно реализовывать IWebDriver в MyWebDriver или, если вы это делаете, вы должны реализовать (написать) все методы интерфейса, такие как FindElement, навигация и многое другое... - person Leon Barkan; 15.08.2016
comment
в этом примере это driver.webDriver.FindElements(By.Id(...)).Click(); если вы используете реализацию и реализуете функцию FindElement с вашим внутренним экземпляром webDriver, вы получите возможность написать driver.FindElement - person Leon Barkan; 15.08.2016
comment
внутренняя функция будет выглядеть примерно так: public IWebElement FindElement(by) { return this.webElement.FindElement(by) } - person Leon Barkan; 15.08.2016
comment
Интерфейс, используемый для того, чтобы классы использовали те же функции, что и IComparable, вы должны написать функцию сравнения, чтобы выполнять операции сравнения с вашими объектами, то же самое для IWebDriver [реализация всех методов сохранит ваш внутренний экземпляр webBrowser в функциях, которые вы реализуете, и сделает ваш код чище] - person Leon Barkan; 15.08.2016
comment
@Milo Представьте, что MyWebDriver — это менеджер, а FirefoxDriver — сотрудник, менеджер реализует IWebDriver и говорит: «Эй, послушай, я могу сделать все это для тебя — но что на самом деле происходит?» Менеджер нанял FirefoxDriver, потому что он также реализует IWebDriver и точно знает, что может просто делегировать всю ответственность ему. Таким образом, для каждого метода, который вам нужно реализовать для IWebDriver, просто делегируйте его драйверу, который вы передаете в конструкторе. Как? общедоступный IWebElement FindElement (по) { return webDriver.FindElement (по); } - person Nick Spicer; 16.08.2016
comment
Спасибо всем за помощь. В конце концов я нашел другое решение моей первоначальной проблемы (которой было правильное ведение журнала результатов теста), реализовав try/catches в правильных местах в моем коде. Далее я задал еще один вопрос, связанный с этим #38960209">здесь - вы можете проверить ответы на возможные способы сделать это. - person Milo; 16.08.2016

Хорошо, давайте прекратим практику половинного ответа (это полная реализация универсального IWebDriver), после чего вы можете вызывать все обычные методы, которые вы используете в стандартном драйвере + у вас есть дополнительная переменная CurrentTest.

вы можете добавить больше конструкторов для лучшей совместимости.

class MyWebDriver<T> where T : IWebDriver, new()
{
    IWebDriver driver;
    public string CurrentTest { get; set; }

    public MyWebDriver()
    {
        driver = new T();
    }

    public void Dispose()
    {
        this.driver.Dispose();
    }

    public IWebElement FindElement(By by)
    {
        return this.driver.FindElement(by);
    }

    public ReadOnlyCollection<IWebElement> FindElements(By by)
    {
        return this.driver.FindElements(by);
    }

    public void Close()
    {
        this.driver.Close();
    }

    public void Quit()
    {
        this.driver.Quit();
    }

    public IOptions Manage()
    {
        return this.driver.Manage();
    }

    public INavigation Navigate()
    {
        return driver.Navigate();
    }

    public ITargetLocator SwitchTo()
    {
        return this.SwitchTo();
    }

    public string Url
    {
        get
        {
            return this.driver.Url;
        }
        set
        {
            this.driver.Url = value;
        }
    }

    public string Title
    {
        get
        {
            return this.driver.Title;
        }
    }

    public string PageSource
    {
        get
        {
            return this.driver.PageSource;
        }
    }

    public string CurrentWindowHandle
    {
        get
        {
            return this.driver.CurrentWindowHandle;
        }
    }

    public ReadOnlyCollection<string> WindowHandles
    {
        get
        {
            return this.WindowHandles;
        }
    }
}

public class MyTest
{
    public void main()
    {
        MyWebDriver<FirefoxDriver> driver = new MyWebDriver<FirefoxDriver>();
        driver.CurrentTest = "Entering to google website with Firefox Driver";
        driver.Navigate().GoToUrl("www.google.com");
    }
}
person Leon Barkan    schedule 16.08.2016
comment
Спасибо за прямой ответ @LeonBarkan! - person Milo; 16.08.2016
comment
Отличный ответ! Единственным недостатком является то, что он не будет работать с RemoteWebDriver, потому что его конструктор принимает аргументы... - person Samuel Rondeau-Millaire; 25.04.2017
comment
Собственно, этот ответ тоже половинчатый. Вы забыли упомянуть using заявления: using OpenQA.Selenium; using System.Collections.ObjectModel; В любом случае, проголосовали за усилия. +1 - person Happy Bird; 03.07.2017
comment
и пространство имен :D - person Leon Barkan; 03.07.2017

что, если вы сделаете что-то вроде

class MyWebDriver
{
   private IWebDriver driver;
   private static string CurrentTest;
   ....
   //make constractors / getters, setters
}

исполнение

MyWebDriver d = new MyWebDriver(....)
...
person Leon Barkan    schedule 15.08.2016
comment
Это имеет смысл! Я постараюсь и отчитаюсь, как только что-то реализую. Спасибо! - person Milo; 15.08.2016

Просто используйте подкласс, который имеет WebDriver в качестве родителя:

public class MyWebDriver : WebDriver
{
    private string _currentTest;
}

Затем вы можете использовать MyWebDriver везде и устанавливать _currentTest по мере необходимости.

person Brendan    schedule 15.08.2016
comment
WebDriver использует интерфейс IWebDriver. Я пробовал вышеописанное, но WebDriver не отображается в IntelliSense, только IWebInterface. Есть ли способ расширить интерфейс? Спасибо. - person Milo; 15.08.2016