Java11 嵌套 类 代码使用 Fluent Design Structure

Java11 Nested Classes while using Fluent Design Structure for code

所以我继承了一个自动化项目(JAVA11 基于使用 Selenium/TestNG),他们希望它重构为代码库使用 Fluent Design,这样非编码人员就可以更容易地开始一个测试构建。有道理......但是......他们在整个页面映射工厂中使用嵌套 JAVA Classes 并且希望仍然保持这种方式。

我擅长 C#,但不擅长 JAVA 和嵌套 Classes。下面是我正在谈论的一个例子。他们基本上想要 Fluent 设计,所以如果他们需要访问嵌套 class,他们可以在 Parent Class 的使用事件中调用它,这样它不会影响链。

我四处寻找使用 Selenium 的示例,但找不到一些。感谢任何帮助。

\Code Base

public class UserAdminPage
{
    @SuppressWarnings("unused")
    private static WebElement element = null;

    public UserAdminPage(RemoteWebDriver driver)
    {
        PageFactory.initElements(driver, this);
    }

    public static UserAdminPage using(RemoteWebDriver driver) 
    {
        return new UserAdminPage(driver);
    }

    public static class AddEditUserInformation
    {
        @FindBy(name = "firstName")
        public WebElement FirstName_txtbx;
        public UserAdminPage FirstName_txtbx(String firstname)
        {
            this.FirstName_txtbx.sendKeys(firstname);
            return this;
        }       

        @FindBy(name = "lastName")
        public WebElement LastName_txtbx;
        public AddEditUserInformation LastName_txtbx(String lastname)
        {
            this.LastName_txtbx.sendKeys(lastname);
            return this;
        }

    }

    @FindBy(id = "AccountsList")
    public WebElement AccountName_dropdwn;
    public void AccountName_dropdwn()
    {
        this.AccountName_dropdwn.click();
    }

    @FindBy(id = "Save_button")
    public WebElement Save_btn;
    public void Save_btn()
    {
        this.Save_btn.click();
    }


}

\Test Event
UserAdminPage.using(driver).AccountName_dropdwn()
                           .AddEditUserInformation.FirstName_txtbx("John")
                           .AddEditUserInformation.LastName_txtbx("Doe")
                           .Save_btn()

静态 public 内部 class 本质上是一个完全独立的 class 并且很容易位于另一个文件中。

您正在调用 AccountName_dropdwn,然后尝试对其 return 值调用一个方法,该值是无效的。您尝试调用的方法是 AddEditUserInformation.FirstName_txtbx,但这是 AddEditUserInformation 的(非静态)成员函数,因此只能在 class 的实例上调用它。您的代码中没有任何地方创建一个。

如果方法 AccountName_dropdwn returned 一个 AddEditUserInformation 对象,我认为您的代码可能会工作。我假设方法名称的不必要限定不会阻止它工作,但它太不寻常了,我不确定。

正如 Zag 在他的回答中指出的那样,您所说的 "nested classes" 实际上是 "regular classes"(因为它们是静态的),这里唯一不寻常的是它们被放置在同一个文件与其他 classes.

除非您愿意做出一些牺牲,否则您无法与 class 没有任何共同点(没有通用接口,不使用泛型)的 "fluent design"。下面的代码显示了使用 "on" 方法的妥协:有一条链,但您需要手动将链从使用一个 class 移动到另一个(这通常是一个很好的 "fluent design" 会隐藏并自动为你做,所以你不必考虑它)。

请注意,下面的代码可以编译并可以执行(通过 "main" 方法)- 如果可能的话,这就是您的代码在问题中的呈现方式。

package so;
public class UserAdminPage {

    public static void main(String[] args) {

        // test code
        System.out.println("Start test.");
        UserAdminPage.using(new RemoteWebDriver())
            .AccountName_dropdwn()
            .onAddEditUserInformation()
            .FirstName_txtbx("John")
            .LastName_txtbx("Doe")
            .onUserAdminPage()
            .Save_btn();
        System.out.println("Finished test.");
    }

    public static UserAdminPage using(RemoteWebDriver driver) {
        return new UserAdminPage(driver);
    }

    private WebElement AccountName_dropdown = new WebElement();
    private WebElement Save_btn = new WebElement();

    public UserAdminPage(RemoteWebDriver driver) {
        PageFactory.initElements(driver, this);
    }

    public UserAdminPage AccountName_dropdwn() {
        AccountName_dropdown.click();
        return this;
    }

    public UserAdminPage Save_btn() {
        Save_btn.click();
        return this;
    }

    public AddEditUserInformation onAddEditUserInformation() {
        return new AddEditUserInformation(this);
    }

    // nested class

    public static class AddEditUserInformation {

        private UserAdminPage page;

        public WebElement FirstName_txtbx = new WebElement();
        public WebElement LastName_txtbx = new WebElement();

        public AddEditUserInformation(UserAdminPage page) {
            this.page = page;
        }

        public AddEditUserInformation FirstName_txtbx(String firstname) {
            this.FirstName_txtbx.sendKeys(firstname);
            return this;
        }       

        public AddEditUserInformation LastName_txtbx(String lastname) {
            this.LastName_txtbx.sendKeys(lastname);
            return this;
        }

        public UserAdminPage onUserAdminPage() {
            return page;
        }
    }

    // external classes

    public static class WebElement {
        public void sendKeys(String keys) {}
        public void click() {}
    }
    public static class RemoteWebDriver {}
    public static class PageFactory {
        public static void initElements(RemoteWebDriver driver, UserAdminPage page) {}
    }

}