0

很抱歉,如果这个问题已经被问过,我还没有找到类似我的问题的东西......

我正在工作/玩耍/学习建立某种测试环境......在其中,我正在构建一个应用程序层(一个类包,是不同页面/窗口/表单的虚拟表示)应用。简化的设置如下:

public abstract class WebPage {

    protected WebDriver driver;

    protected WebElement getElement(By by){
        WebElement element = (new WebDriverWait(driver, 10))
              .until(ExpectedConditions.presenceOfElementLocated(by));

    return element;
}

    public void menuLogout(){
        System.out.println("Logged out");
    }
}

public class HomePage extends WebPage {

    public ProfilePage ClickLinktoProfilePage(){
        return new ProfilePage();
    }

    public DashBoardPage clickViewDashboard(){
        return new DashBoardPage();
    }

    public String getTitle(){
        return getElement(By.id("title")).getText();
    }
}

public class ProfilePage extends WebPage {

    public String getUsername(){
        return getElement(By.id("name")).getText();
    }

    public String getEmail(){
    return getElement(By.id("email")).getText();
}       
    public HomePage clickReturnToHomePage(){
        return new HomePage();
    }

}

public class DashBoardPage extends WebPage {

    public String getcurrentPeriod(){
        return getElement(By.id("name")).getText();

}
}

这背后的想法是我希望我的测试只保存一个当前网页。我不希望每次更改页面时都创建一个新变量。

我也不想被迫提前知道我要进入哪个页面。我希望应用程序层给我应用程序的流程。就像单击链接时,您会被带到下一页一样,我希望当我单击将我带到另一个页面的链接时,该方法会告诉我我将进入哪个页面。

(WebPage 抽象类还公开了所有具体 WebPage 之间的许多共享方法)

所以我的预期用途是:

WebPage currentPage = new HomePage();

currentPage = currentPage.ClickLinktoProfilePage(); //currentPage = new ProfilePage();
System.out.println(currentPage.getUsername());
currentPage.menuLogout();

遗憾的是,这不起作用,因为 currentPage 变量被键入为 WebPage,它看不到任何具体类的方法。我觉得它既合乎逻辑又很奇怪,因为我可以问“currentPage.getClass().getName();” 它会返回“packageName.ConcreteClassName”。

为了使 Typecasting 起作用,我需要重新定义变量的类型......(不确定它是否可能甚至是好做)。

所以我知道我可以在变量中找到类的名称,但我不确定从那里去哪里。

有人有解决方案吗?

4

1 回答 1

2

为了澄清 Radiodef 和我在这里的评论中所说的话:

您想要的是以WebPage这样一种方式定义(您的抽象 API),即您的具体子类不需要具有不属于该 API 的公共方法。

比如比较java.util.List标准库中的接口。这个接口有多种实现(ArrayList并且LinkedList是最著名的,但还有很多其他的),但是大多数使用的代码List不需要关心它实际上是在使用 anArrayList还是 aLinkedList或其他东西,因为所有您需要的操作通过List接口公开。

你可以对你的WebPage班级做同样的事情。例如,您可以为可以对网页执行的不同操作定义一系列“钩子”:

public abstract class WebPage {
  // methods that each subclass needs to implement
  protected abstract String renderBodyHtml();
  public abstract String getNameToLinkTo();

  // other methods that are common to every page
  public final void serve(
      HttpServletRequest request, HttpServletResponse response) {
     // write the response, using the specific page's body HTML
     response.getWriter().println(renderToBodyHtml());
  }
}

然后您的页面将像这样实现该合同

// Note: the class doesn't need to be public, since anybody that uses
// it can just declare their variable as type WebPage
class Page1 extends WebPage {
  @Override protected String renderBodyHtml() {
    return "<body>Hello world!</body>";
  }

  @Override public String getNameToLinkTo() {
     return "Page1";
  }
}

那么想要使用 a 的代码WebPage不需要知道它是 a Page1(或任何其他页面):

public static void printPageName(WebPage webPage) {
  System.out.println(webPage.getNameToLinkTo());
}

或者,就像 resueman 所说,您可以直接使用Page1,Page2等类型,WebPage仅用于实现继承,而不是 API。这也很好——正确的解决方案取决于您希望代码的灵活性(和复杂性)。

于 2015-04-14T18:48:18.790 回答