简体   繁体   English

扩展方法可以使用非静态字段吗?

[英]Can extension methods use non-static fields?

I'm not sure if this preamble is necessary (in its entirety or at all) but I think it conveys my use-case for needing to use a non-static field inside a static extension method.我不确定这个序言是否必要(全部或根本),但我认为它传达了我需要在静态扩展方法中使用非静态字段的用例。

I have a test suite implemented with Selenium/C#/NUnit.我有一个用 Selenium/C#/NUnit 实现的测试套件。

I used to use PageFactory to define my page elements.我曾经使用PageFactory来定义我的页面元素。 PageFactory has been deprecated so it seemed logical to switch to defining my elements as IWebElements: PageFactory 已被弃用,因此切换到将我的元素定义为 IWebElements 似乎是合乎逻辑的:

HomePage.cs...主页.cs...

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

The trouble with this approach is that prior to any tests being run, this file is read, line by line, and the DOM is being queried for all of these elements before my tests try to use them.这种方法的问题在于,在运行任何测试之前,会逐行读取该文件,并且在我的测试尝试使用它们之前,会查询所有这些元素的 DOM。 They are throwing ElementNotFound exceptions because of course - at the time the elements are being queried, no test has been run yet, which means we're not even on the homepage to interact with them.当然,它们抛出 ElementNotFound 异常是因为 - 在查询元素时,尚未运行任何测试,这意味着我们甚至不在主页上与它们进行交互。

To resolve this, I changed the type of the elements to By:为了解决这个问题,我将元素的类型更改为 By:

HomePage.cs...主页.cs...

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

This allows me to define the elements, then query the DOM at the right time.这允许我定义元素,然后在正确的时间查询 DOM。 Great, problem solved.太好了,问题解决了。 Except, now I have another problem.除了,现在我还有另一个问题。 I liked being able to chain methods off of the IWebElements, for readability purposes:我喜欢能够从 IWebElements 链接方法,以提高可读性:

LoginButton.Click();

But the 'By' type doesn't contain the methods that IWebElement does.但是“By”类型不包含 IWebElement 所做的方法。 So the next logical step is: create an extension method.所以下一个合乎逻辑的步骤是:创建一个扩展方法。

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

Great, problem solved.太好了,问题解决了。 Except, now I have another problem.除了,现在我还有另一个问题。 My test suite cannot use a static IWebDriver because I want to execute my tests in parallel.我的测试套件不能使用静态 IWebDriver,因为我想并行执行我的测试。 Sadly, the extension method approach requires that the driver is static.遗憾的是,扩展方法方法要求驱动程序是静态的。

So unless I can somehow use my non-static IWebDriver inside the extension method, it looks like I cannot achieve my goal of chaining methods off of the 'By' elements...因此,除非我能以某种方式在扩展方法中使用我的非静态 IWebDriver,否则看起来我无法实现从“By”元素中链接方法的目标......

I had to find a replacement for Page Factory also.我还必须找到 Page Factory 的替代品。 Fortunately C# has handy feature called Expression-bodied members .幸运的是,C# 有一个方便的特性叫做Expression-bodied members

In case of your HomePage, elements would be:如果是您的主页,元素将是:

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

Selenium will search for those elements during execution, not at the beginning, so exceptions will not be thrown. Selenium 将在执行期间而不是在开始时搜索这些元素,因此不会抛出异常。

Can extension methods use non-static fields?扩展方法可以使用非静态字段吗?

No.不。

So unless I can somehow use my non-static IWebDriver inside the extension method, it looks like I cannot achieve my goal of chaining methods off of the 'By' elements...因此,除非我能以某种方式在扩展方法中使用我的非静态 IWebDriver,否则看起来我无法实现从“By”元素中链接方法的目标......

Just pass your driver object to the extension method and use it.只需将您的驱动程序对象传递给扩展方法并使用它。

Example:例子:

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

I'm answering this as well to expand on the answers already given (I mentioned chaining methods off of the 'By' type).我也在回答这个问题以扩展已经给出的答案(我提到了“By”类型的链接方法)。

So to do this I discovered that I should make the extension methods have the 'By' type, and return the same By reference I was using...所以要做到这一点,我发现我应该让扩展方法具有“By”类型,并返回我正在使用的相同 By 引用......

    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;
    }

This allows me to do the following:这使我可以执行以下操作:

            HomePage homePage = new HomePage(_driver);

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

Not that I'd click the same thing twice, this is just a quick example.并不是说我会点击同一个东西两次,这只是一个简单的例子。 Now to do this elegantly by not referencing the driver in every extension method call...现在通过不在每个扩展方法调用中引用驱动程序来优雅地做到这一点......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM