我们的开发团队正在开发新的页面模板,其中包括对这些页面上定位器的大量更改。这些新页面位于切换位置,因此它们可能会在我们的测试环境中随时出现,也可能不会出现,具体取决于它们是打开还是关闭。 标头中有一个id,我可以用它来识别是否切换了新的页面模板。 任何人都可以告诉我处理这个问题的最佳方法。理想情况下,我想将新的定位器添加到相关的页面对象中,而不是将它们放在属性文件中。
当前定位器和WebElement:
@FindBy(className = "add-to-cart-btn")
WebElementFacade addToCartBtn;
新模板上的新定位器:
className = "quickOrderSubmit"
答案 0 :(得分:0)
找出一种方法,通过使用自定义ElementLocatorFactory, ElementLocator and Annotations
类将旧定位器和新定位器保持在同一位置。这些将很容易地适应页面对象模型。它使用了FindBy注释的using
和locator value (id,class,css,xpath etc)
字段的组合。这是FindBy使用的黑客攻击。一个新的注释会更好,但这是太多的工作。
这将通过在pageobject类的构造函数中使用以下代码集成到PageFactory initElements方法中。
OldNewElementLocatorFactory onelf = new OldNewElementLocatorFactory(driver);
PageFactory.initElements(onelf, this);
用法 -
@FindBy(使用=" id @@ id",id =" newid @@ oldid")或@FindBy(使用=&#34 ;名称@@ name",name =" newname @@ oldname")
使用部分 - 分隔符前面的第一部分是新定位器的定位器策略,第二部分是旧定位器。
ID部分 - 第一部分是新定位器策略的值,第二部分是旧的值。
@FindBy(使用="名称@@ id",名称="新名称",id =" oldid")或@FindBy(使用=" xpath @@ css",xpath =" // div / input [@id =' comboid2']",css =&# 34; div输入[id =' comboid2']")
使用部分 - 与上述相同。
名称部分 - 新名称策略的定位器值。
ID部分 - 旧ID策略的定位器值。
@FindBy(使用="类@@ tag",className =" newClass",tagName ="输入") 私人清单输入;
@FindBy(使用="类@@ class",className =" newClass @@ oldClass") private List sameInputs;
ElementLocatorFactory
- 字段isNew and oldNewChecked
管理是否使用新定位符或旧定位符的问题。这些都在这个类中,因为定位器可以在页面级别上变化。如果您不使用Java8,则需要修改verifyPageAge()
方法。注意确保只搜索旧的新定位器开关一次。
public class OldNewElementLocatorFactory implements ElementLocatorFactory {
private final SearchContext searchContext;
private boolean isNew = false;
private boolean oldNewCecked = false;
public OldNewElementLocatorFactory(SearchContext searchContext) {
this.searchContext = searchContext;
}
public ElementLocator createLocator(Field field) {
OldNewElementLocator elemLoc = new OldNewElementLocator(searchContext, field);
elemLoc.setFactory(this);
return elemLoc;
}
public void verifyPageAge(Supplier<Boolean> newLoc) {
if (!oldNewCecked) {
oldNewCecked=true;
if (newLoc.get())
isNew=true;
}
}
public boolean isNew() {
return isNew;
}
public void setNew(boolean isNew) {
this.isNew = isNew;
}
public boolean isOldNewCecked() {
return oldNewCecked;
}
public void setOldNewCecked(boolean oldNewCecked) {
this.oldNewCecked = oldNewCecked;
}
}
ElementLocator
- 它处理方法verifyNewLocators()
中新旧定位器开关的搜索。您需要修改此方法以搜索您的标志。我假设任何id为newloc的元素。如果不是在Java8上,则需要修改方法createOldNewBy()
。
public class OldNewElementLocator implements ElementLocator {
private final SearchContext searchContext;
private final boolean shouldCache;
private By by = null;
private WebElement cachedElement;
private List<WebElement> cachedElementList;
private OldNewAnnotations annotations;
private OldNewElementLocatorFactory factory;
public OldNewElementLocator(SearchContext searchContext, Field field) {
this(searchContext, new OldNewAnnotations(field));
}
public OldNewElementLocator(SearchContext searchContext, OldNewAnnotations annotations) {
this.searchContext = searchContext;
this.shouldCache = annotations.isLookupCached();
this.annotations = annotations;
this.by = annotations.buildBy();
}
public OldNewElementLocatorFactory getFactory() {
return factory;
}
public void setFactory(OldNewElementLocatorFactory factory) {
this.factory = factory;
}
protected boolean verifyNewLocators() {
return (searchContext.findElements(By.id("newloc")).size() == 1) ? true : false;
}
protected void createOldNewBy() {
factory.verifyPageAge(this::verifyNewLocators);
if(by==null) {
by = annotations.buildOldNewBy(factory.isNew());
}
System.out.println(by.getClass().getSimpleName());
}
public WebElement findElement() {
if (cachedElement != null && shouldCache) {
return cachedElement;
}
createOldNewBy();
WebElement element = searchContext.findElement(by);
if (shouldCache) {
cachedElement = element;
}
return element;
}
public List<WebElement> findElements() {
if (cachedElementList != null && shouldCache) {
return cachedElementList;
}
createOldNewBy();
List<WebElement> elements = searchContext.findElements(by);
if (shouldCache) {
cachedElementList = elements;
}
return elements;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + " '" + by + "'";
}
}
Annotations
- 它管理用于创建By对象的解析逻辑。还包含我使用的硬编码分隔符 - @@。更改它或为此创建一个静态字段。
public class OldNewAnnotations extends Annotations {
public OldNewAnnotations(Field field) {
super(field);
}
public By buildBy() {
if (assertNewOldFind())
return null;
return super.buildBy();
}
public By buildOldNewBy(boolean isNew) {
if (!assertNewOldFind())
throw new IllegalArgumentException(
"If you set the 'using' property, you cannot also set 'how'");
FindBy findBy = getField().getAnnotation(FindBy.class);
String[] using = findBy.using().split("@@");
String strategy = isNew ? using[0] : using[1];
switch (strategy) {
case "id":
return By.id(getStrategyLocator(findBy.id(), isNew));
case "name":
return By.name(getStrategyLocator(findBy.name(), isNew));
case "class":
return By.className(getStrategyLocator(findBy.className(), isNew));
case "css":
return By.cssSelector(getStrategyLocator(findBy.css(), isNew));
case "xpath":
return By.xpath(getStrategyLocator(findBy.xpath(), isNew));
case "link":
return By.linkText(getStrategyLocator(findBy.linkText(), isNew));
case "partiallink":
return By.partialLinkText(getStrategyLocator(
findBy.partialLinkText(), isNew));
case "tag":
return By.tagName(getStrategyLocator(findBy.tagName(), isNew));
}
return null;
}
private String getStrategyLocator(String value, boolean isNew) {
if (value.contains("@@")) {
String[] val = value.split("@@");
return isNew ? val[0] : val[1];
}
return value;
}
protected boolean assertNewOldFind() {
FindBys findBys = getField().getAnnotation(FindBys.class);
if (findBys != null) return false;
FindAll findAll = getField().getAnnotation(FindAll.class);
if (findAll != null) return false;
FindBy findBy = getField().getAnnotation(FindBy.class);
if (findBy.how() == How.UNSET && !"".equals(findBy.using()))
return true;
return false;
}
}
缺点 -
检查新注释用法格式的错误并不多。你可以看看它是否健壮。
它不会同时处理旧定位器和新定位器的FindBys和FindAll注释。它可能很容易,但Selenium源有一些私有方法,这使得很难通过继承来覆盖。您可以考虑采用不同的方法来解决它。虽然几乎没有看到这些注释使用过。