我被要求创建一个应用程序,使用Java,Selenium和PhantomJS填写表单并将表单提交给第三方网站(我是实习生,所以这对我来说都很新鲜。)
这需要在十几个不同的页面上弹跳。我正在使用Page Object模型,每个页面都有不同的类。我的问题是:
初始化所有页面对象的最佳方法是什么?
我目前正在这样做。我在设置过程中初始化了几个页面:
public class MyProject
{
private HomepagePageObject homepagePageObject;
private SecondpagePageObject secondpagePageObject;
private ThirdpagePageObject thirdpagePageObject;
private FourthpagePageObject fourthpagePageObject;
private WebDriver driver;
public MyProject()
{
driver = new PhantomJSDriver();
driver.get("http://www.homepage.com");
homepagePageObject = new HomepagePageObject(driver);
homepagePageObject.clickButtonForSecondPage();
secondpagePageObject = new SecondpagePageObject(driver);
secondpagePageObject.clickButtonForThirdPage();
thirdpagePageObject = new ThirdpagePageObject(driver);
}
}
在设置过程中无法访问某些页面(即确认提交的页面)。因此,每当我遇到可能已初始化的页面时,我都会这样做:
if(fourthpagePageObject == null)
fourthpagePageObject = new FourthpagePageObject(driver);
这似乎是一种混乱的方式来做到这一点。是否有最佳实践'用于在您不知道访问页面的顺序时初始化页面对象?
答案 0 :(得分:1)
我们正在使用工厂类,如下所示:
class PagesFactory{
private WebDriver driver;
public HomePage getHomePage(){
return new HomePage( driver );
}
// if you want to share the same object (singleton) among many tests
private SecondPage secondPage;
public SecondPage getSecondPage(){
if( secondPage == null ){
secondPage = new SecondPage( driver );
}
return secondPage( driver );
}
.....
.....
}
在我们的项目中,我们使用Spring来实例化WebDriver并将其注入到许多工厂类中(我们有十几个工厂,每个工厂都对我们应用程序不同部分的页面进行分组)。
在测试类中,我们简单地获得所需的工厂,并且当需要某个页面时,所有测试方法都只是引用工厂对象
在Java中,它可以通过以下方式完成(但我们也使用Spring来实例化并将工厂注入到我们的测试类中):
class TestSomePartOfApplication{
KKKPages kkkPages = KKKPages.getInstance();
AtosPages atosPages = AtosPages.getInstance();
.....
void testScenario1(){
kkkPages.getPageA.fillField("Field name 1", 120 );
kkkPages.getPageA.clickButtonOK();
......
}
void testScenario2(){
kkkPages.getPageB.fillField("Field 15", "abc" );
kkkPages.getPageA.clickButtonOK();
atosPages.getPageC.fillField("Field 33", "Client name");
......
}
}
自从你在问题中写道
在设置过程中无法访问某些页面(即确认的页面) 提交)。因此,每当我遇到可能会或可能不会的页面时 已初始化,我这样做:
所以我猜你正在使用一种导航策略,其中页面对象负责创建另一个页面的新页面对象,如果某些操作指向这个新页面的话。这是随处可见的常见建议。您可以在许多与页面对象模式相关的文章中找到此策略的示例,通常是登录页面的典型示例:
class LoginPage{
public HomePage loginUaer( String user, String password ){
// fill in fields and click Login button
.....
.....
return new HomePage( .... );
}
}
但是我们发现这个策略很难在复杂的应用程序中使用,其中许多页面由许多共同元素组成,但仅在细节方面彼此不同。这种方法增加了项目的复杂性,因为许多类必须相互耦合,在许多情况下页面对象必须是有状态的,并且必须记住在页面上执行的先前操作,或者必须使用其他一些方法(检查页面) / window content?)决定导航是否可以完成,以及导航类型(例如 - 当用户输入错误的密码时,则显示一个错误消息页面,如果他将字段留空,则显示另一个页面,如果用户名和密码都没问题,那么他就转发到主页等等。)。为此,必须在页面对象中实现一些复杂的规则,这些规则模仿应用程序的行为 - 这非常费力且容易出错。
我们正在使用另一种策略,如下所述:
http://martinfowler.com/bliki/PageObject.html
让页面对象负责创建其他页面对象 对导航等事情的回应是常见的建议。不过有的 从业者更喜欢页面对象返回一些通用浏览器 上下文,测试控制在哪个页面对象上构建 基于测试流程的上下文(特别是有条件的 流程)。他们的偏好是基于测试脚本的事实 知道接下来会有哪些页面,而这些知识并不需要 在页面对象本身中重复。他们增加他们的 使用通常显示的静态类型语言时的首选项 类型签名中的页面导航。
这种方法对我们非常有效。我们有很多独立的,解耦的和无状态的类(POJO),它们在页面上实现非常简单的操作 - 甚至只在页面的某个部分(部分)上实现。想象一下,有数百个页面共享一个共同的元素(如客户列表,客户数据部分,附件部分,消息部分等),并且它们彼此之间略有不同(一页)有A,B,C部分,另一个有B,C,D等)。为每个页面创建一个单独的页面对象是不切实际的(数百个clases - 这是一场噩梦)。对于每个这样的部分,我们只有几个独立的页面对象,导航流程在测试本身中实现,如:
pageFactoryA.getSectionAPage().clickButtonB();
pageFactoryB.getSectionBPage.fillInCustomerField( customerName );
pageFactoryA.getSectionCPage.clickButton("Display customer report");
// the above operation should display a new page: Customer Report
// so we get a CustomerReportPage from the factory
int total = pageFactoryC.getCustomerReportPage().getTotal();
assertEquals( total, 2000 );
.....