我们的开发团队正在开发新的页面模板,其中包括对这些页面上的定位器的大量更改。这些新页面处于切换状态,因此在我们的测试环境中,它们可能随时存在,也可能不存在,这取决于它们是否被切换打开或关闭。标头中有一个id,我可以用它来标识新页面模板是否被切换。谁能告诉我处理这件事的最好方法。理想情况下,我希望将新的定位器添加到相关的页面对象,而不是将它们放在属性文件中。
当前定位器和Web元素:
@FindBy(className = "add-to-cart-btn")
WebElementFacade addToCartBtn;
新模板上的新定位器:
className = "quickOrderSubmit"
通过使用自定义的ElementLocatorFactory、ElementLocator和Annotations
类,找到了一种将新旧定位器保持在同一位置的方法。这些将很容易适应页面对象模型。它结合使用和
定位器值(id、class、css、xpath等)
字段的FindBy注释。这是对FindBy用法的一种破解。一个新的注释会更好,但这是太多的工作。
这将通过在pageobject类的构造函数中使用下面的代码集成到PageFactory initElements方法中。
OldNewElementLocatorFactory onelf = new OldNewElementLocatorFactory(driver);
PageFactory.initElements(onelf, this);
用法-
新旧定位策略相同。例如id已更改。
@FindBy(使用=“id@@id”,id=“newid@@oldd”)或@FindBy(使用=“name@@name”,name=“newname@@oldname”)
使用部分分隔符前的第一部分是新定位器的定位器策略,第二部分是旧定位器的定位器策略。
id部分-第一部分是新定位器策略的值,第二部分是旧定位器策略的值。
新旧定位策略不同。例如,id现在已更改为name
@FindBy(使用=“name@@id”、name=“newname”、id=“oldid”)或@FindBy(使用=“xpath@@css”、xpath=“//div/input[@id='comboid2']”,css=“div input[id='comboid2']”)
使用部分-同上。
名称部件-新名称策略的定位器值。
id部件-旧id策略的定位器值。
这同样适用于与列表类型变量一起使用的FindBy
@findBy(使用="class@@tag", class Name="newClass", tagName="输入")私有列表输入;
@findBy(使用="class@@class", class Name="newClass@@oldClass")私有列表sameInput;
允许使用标准格式的FindBy注释。无需更改@FindBy(how=how.ID,using=“origid”)或@FindBy(ID=“origid”)
ElementLocatorFactory
-字段为新建和已选中的旧定位器
管理使用新定位器还是旧定位器的问题。这些都属于此类,因为定位器在页面级别上可能会有所不同。如果您没有使用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 + "'";
}
}
注释
-这管理用于创建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 source有一些私有方法,这使得通过继承使用重写变得很困难。你可以用不同的方法来解决这个问题。虽然很少看到使用这些注释。
问题内容: 如果我从未检查过Go通道的状态,可以永远保持打开状态(永远不关闭通道)可以吗?会导致内存泄漏吗?下列代码可以吗? 问题答案: 可以永远保持Go频道永远不关闭。当不再使用该通道时,将对其进行垃圾回收。 请注意,只有当接收器正在寻找关闭通道时,才需要关闭通道。关闭通道是通道上的控制信号,指示没有更多数据跟随。 设计问题:通道关闭
在Eclipse中运行TomCat。我在浏览器http://localhost:8080/springmvc/index.jsp中键入,然后看到“Hello World!”。 我的配置
为何这个网页可以在我的浏览器打开 https://fiin-core.ssi.com.vn/Master/GetListOrganization?langu... 但是 https://fiin-core.ssi.com.vn/ 域名为何无法打开呢?
我是测试自动化的初学者,尝试学习硒。 我用C#实现了selenium Chrome Webdriver的自动化 多谢了。
问题内容: 我正在通过com端口连续接收数据并进行一些解码。解码完成后,我必须将结果存储在sql数据库中。我在想,因为解码是每秒完成数十次(在while循环中始终运行),并且如果明智的做法是打开和关闭与sql server的连接,则每秒需要将数据存储到数据库数十次。每个while循环或只是使其保持打开状态并继续将数据写入数据库。首先这可能吗?其次,如果连接保持打开状态,那么第三方应用程序或计算机可
我正在开发这个Android应用程序,它应该为普通和大屏幕设备使用相同的布局。但是对于所有的屏幕尺寸落入xlarge括号中,我希望系统使用这个Android文档描述的屏幕兼容模式。 本文件明确指出: 默认情况下,当以下情况之一为真时,运行Android 3.2及更高版本的设备的屏幕兼容模式作为可选功能提供给用户: > < li> 您的应用程序已将android:minSdkVersion和andr