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) {}
}
}
所以我继承了一个自动化项目(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) {}
}
}