Selenium 页面对象重用
我真的很喜欢 selenium 2 按照惯例推动您使用 PageObjects 作为 POJO,然后简单地使用 PageFactory 来实例化此类中的字段。
我发现限制是我们在许多不同的页面上重复使用许多元素。最大的问题是,这些复用的组件出现在不同页面时,没有相同的 id/name;然而,我们为每个人运行的测试是相同的。
例如,我们在很多地方收集日期。因此,一个示例页面对象可以是(删除月、日字段):
public class DatePageObject {
private WebDriver driver;
DatePageObject(WebDriver driver) {
this.driver = driver;
}
@FindBy( id = "someIdForThisInstance")
private WebElement year;
public void testYearNumeric() {
this.year.sendKeys('aa');
this.year.submit();
//Logic to determine Error message shows up
}
}
然后我可以简单地使用下面的代码测试它:
public class Test {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
DatePageObject dpo = PageFactory.initElements(driver, DriverPageObject.class);
driver.get("Some URL");
dpo.testYearNumeric();
}
}
我真正想做的是进行一个设置,通过 Spring 我可以注入该 id/name /xpath 等...进入应用程序。
有没有办法可以在不失去使用 PageFactory 的能力的情况下做到这一点?
编辑 1 - 添加理想的基础级别类,处理自定义定位器和工厂。
public class PageElement {
private WebElement element;
private How how;
private String using;
PageElement(How how, String using) {
this.how = how;
this.using = using;
}
//Getters and Setters
}
public class PageWidget {
private List<PageElement> widgetElements;
}
public class Screen {
private List<PageWidget> fullPage;
private WebDriver driver;
public Screen(WebDriver driver) {
this.driver = driver;
for (PageWidget pw : fullPage) {
CustomPageFactory.initElements(driver, pw.class);
}
}
编辑 2——请注意,只要您运行 Selenium 2.0.a5 或更高版本,您现在就可以为驱动程序提供隐式超时值。
因此您可以将代码替换为:
private class CustomElementLocator implements ElementLocator {
private WebDriver driver;
private int timeOutInSeconds;
private final By by;
public CustomElementLocator(WebDriver driver, Field field,
int timeOutInSeconds) {
this.driver = driver;
this.timeOutInSeconds = timeOutInSeconds;
CustomAnnotations annotations = new CustomAnnotations(field);
this.by = annotations.buildBy();
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS); //Set this value in a more realistic place
}
public WebElement findElement() {
return driver.findElement(by);
}
}
I really like how selenium 2 by convention pushes you towards using PageObjects as POJOs, and then simply using the PageFactory to instantiate the fields in this class.
What I am finding limiting is that we reuse a lot of elements on many different pages. The big problem is that these reused components do not have the same id / name when they appear on different pages; however the tests we would run for each of them is the same.
As an example we collect dates in many places. So an example page object for this could be (month, day fields removed):
public class DatePageObject {
private WebDriver driver;
DatePageObject(WebDriver driver) {
this.driver = driver;
}
@FindBy( id = "someIdForThisInstance")
private WebElement year;
public void testYearNumeric() {
this.year.sendKeys('aa');
this.year.submit();
//Logic to determine Error message shows up
}
}
Then I could simply test this with the code below:
public class Test {
public static void main(String[] args) {
WebDriver driver = new FirefoxDriver();
DatePageObject dpo = PageFactory.initElements(driver, DriverPageObject.class);
driver.get("Some URL");
dpo.testYearNumeric();
}
}
What I'd really like to do is have a setup whereby with Spring I can inject that id/name/xpath, etc... into the application.
Is there a way I can do this, without losing the ability to utilize the PageFactory?
Edit 1 -- Adding ideal base level classes, working on Custom Locators and Factories.
public class PageElement {
private WebElement element;
private How how;
private String using;
PageElement(How how, String using) {
this.how = how;
this.using = using;
}
//Getters and Setters
}
public class PageWidget {
private List<PageElement> widgetElements;
}
public class Screen {
private List<PageWidget> fullPage;
private WebDriver driver;
public Screen(WebDriver driver) {
this.driver = driver;
for (PageWidget pw : fullPage) {
CustomPageFactory.initElements(driver, pw.class);
}
}
Edit 2 -- Just as a note, as long as you are running Selenium 2.0.a5 or greater, you can now give the driver an implicit timeout value.
So you can replace your code with:
private class CustomElementLocator implements ElementLocator {
private WebDriver driver;
private int timeOutInSeconds;
private final By by;
public CustomElementLocator(WebDriver driver, Field field,
int timeOutInSeconds) {
this.driver = driver;
this.timeOutInSeconds = timeOutInSeconds;
CustomAnnotations annotations = new CustomAnnotations(field);
this.by = annotations.buildBy();
driver.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS); //Set this value in a more realistic place
}
public WebElement findElement() {
return driver.findElement(by);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以构建通用 Web 元素的页面对象(刚刚发明了这个名称:)) - 每个 CWE 将代表一个在不同页面上使用的“小部件”。在您的示例中,这将是某种日期小部件 - 它包含年、月和日。基本上它将是一个页面对象。
PageFactory
要求在@FindBy
注释中使用字符串常量。为了解决这个限制,我们创建了自己的 ElementLocator。
您可以在测试中使用
DateWidget
:包含自定义定位器和注释解析器的
DateWidget
类是:You can build your Page Object of the Common Web Elements (just invented this name :)) - each CWE will represent a "widget" that is used on different pages. In your example this will be a some sort of Date Widget - it contains the Year, Month and a Day. Basically it will be a Page Object.
PageFactory
requires the string constants to be used in@FindBy
annotations.To resolve this limitation we created our own
ElementLocator
s.You can use the
DateWidget
in your test:The
DateWidget
class, which contains custom locators and annotation parsers is: