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

Can extension methods use non-static fields?

我不确定这个序言是否有必要(完整或根本没有),但我认为它传达了我的用例需要在静态扩展方法中使用非静态字段。

我有一个用 Selenium/C#/NUnit 实现的测试套件。

我曾经使用 PageFactory 来定义我的页面元素。 PageFactory 已被弃用,因此切换为将我的元素定义为 IWebElements:

似乎合乎逻辑

HomePage.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:

HomePage.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' 元素链接方法的目标...

Can extension methods use non-static fields?

没有

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...

只需将您的驱动程序对象传递给扩展方法并使用它。

示例:

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

我还必须找到 Page Factory 的替代品。幸运的是 C# 有一个叫做 Expression-bodied members.

的方便的特性

如果是您的主页,元素将是:

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

Selenium 会在执行期间搜索那些元素,而不是在开始时,因此不会抛出异常。

我也在回答这个问题,以扩展已经给出的答案(我提到了 'By' 类型的链接方法)。

所以为了做到这一点,我发现我应该使扩展方法具有 'By' 类型,并且 return 与我使用的相同

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

并不是说我会点击同一个东西两次,这只是一个简单的例子。现在通过不在每个扩展方法调用中引用驱动程序来优雅地做到这一点...