我可以使用数组或哈希映射在页面对象模型中组织对象吗?

我是Selenium自动化的新手。 我对java有很好的了解。

我创建了用于用户注册的测试脚本。

我已经使用了页面对象模型。 这是我的页面对象脚本。

这是我用的

public class SIgnUpTest extends PageObject { @FindBy(id="merchantName") private WebElement merchant; @FindBy(id="merchantCode") private WebElement code; @FindBy(id="categoryId") private WebElement category; @FindBy(id="description") private WebElement description; @FindBy(id="merchantLogo") private WebElement logo; @FindBy(id="btnNextStep1") private WebElement Next; public SIgnUpTest(WebDriver driver) { super(driver); } public void enterName(String name, String code,String description){ this.merchant.sendKeys(name); this.code.sendKeys(code); this.description.sendKeys(description); } public void Logo(String Logo){ this.logo.sendKeys(Logo); } public void Next() { Next.click(); } 

我有大约100个像这样添加的对象。 我该如何组织这个以供长期使用?

有没有办法比重复使用@Find by和WebElement?

我已经找了数组和哈希映射。 但我不知道如何使用它。

我可以使用二维数组或哈希映射吗? 如果是这样的话?

谢谢。

我想要这样的东西使用。 可能吗?

有什么方法可以使用类似于以下内容的东西:

以下代码有问题。

 public class SIgnUpTest extends PageObject { public void objects (){ SortedMap sm = new TreeMap(); sm.put("merchantName", "merchant"); sm.put("merchantCode", "code"); sm.put("categoryId", "category"); sm.put("description", "description"); sm.put("merchantLogo", "Logo"); sm.put("Next", "Next") for(int i=0; i<sm.keySet().size(); i++){ @FindBy(id=sm.keySet()); } for(int i=0; i<sm.keySet().size(); i++){ private WebElement sm.values(); } } public SIgnUpTest(WebDriver driver) { super(driver); } public void enterName(String name, String code,String description){ this.merchant.sendKeys(name); this.code.sendKeys(code); this.description.sendKeys(description); } public void Logo(String Logo){ this.logo.sendKeys(Logo); } public void Next() { Next.click(); } } 

是的,有多种方法可以解决这个问题。 我猜你有一个很大的页面,你需要与很多元素进行交互。 不使用pagefactory方法的方法之一(通常与PageObject模型混淆)。

您可以使用驱动程序实例在需要时使用driver.findElement(By.xpath("//xpath/to/element"));查找所需的driver.findElement(By.xpath("//xpath/to/element"));

或者,您可以使用内部类在逻辑上封装页面上的不同模块。 我建议您先阅读以下链接,以便更清楚地了解设计决策:

https://sqa.stackexchange.com/questions/14889/how-do-i-split-my-pageobject-model-classes https://martinfowler.com/bliki/PageObject.html

根据我的经验,我喜欢ObjectMap -over- PageObject。

ObjectMap(有助于避免学习整个PageObj复杂的抽象层和分类法)可以在— Selenium Testing Tools Cookbook,2nd Edition — book and seleniumeasy中找到 。 将其视为组合 – 遗传 ,支持更灵活和更强大的组合,避免设计复杂的分类法。 还支持数据驱动方法,选择器不是在代码中硬编码==无法配置。 PageObj将您的代码与复杂的抽象联系起来,因此为了重用它,您总是需要在您的网站中使用此特定页面。 配置文件有它们的位置,但是当它们与代码打包在一起并且不打算由用户更新时,更新配置文件中的值和在代码中更新它所需的步骤一样多,所以有真的没有封装发生。 动态表单(PageObj / BEM )基于测试需求构建运行时。 没有复杂forms的分类法。

 basic_contact > zip_code_contact > dealer (message+dealer info header) > quote (model+trim) > test_drive (calendar) > contact_us (email+chat) 

在进入POM(如holmium.core和page-objects )之前,请先考虑以下几点 :

  1. 自动构建的页面对象很难维护和使用。 几乎没有元素分组成页眉和页脚,或者识别出小部件,只会有大量的东西 – 并且自动生成的名称是否能够很好地解释它们的用途?

  2. 它可能会限制您的设计,例如您盯着忽略更好的抽象。

  3. 灵活性不足,特别是对于重构(结构和实现)。

在dzone了解更多信息 。 在这里和这里实现Java。

您需要创建自定义注释,elementfactory和decorator来完成此任务。 在下面的代码中添加适当的导入。

注解

 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface MultipleFind { String delimiter() default "@@"; String[] elementDetails(); } 

示例PageObjectusernameInput @@ ID @@ username第一部分将用作Map中的second part定位器策略 ,这将对应于How.java enum的值。 第三部分定位器 。 此页面对象可以包含标准注释,如FindBy等以及自定义注释。

 public class LoginPageObject extends BasePageObject { //Conventional declaration @FindBy(how=How.ID, using="username") private WebElement usernameInput; //Conventional declaration @FindBy(how=How.NAME, using="pwd") private WebElement passwordInput; //Custom multiple annotation @MultipleFind(elementDetails = { "usernameInput@@ID@@username", "passwordInput@@NAME@@pwd" }) private Map loginui; public LoginMapPageObject(WebDriver driver) { super(driver); //PageFactory initialization with custom factory and decorator MapElementLocatorFactory melf = new MapElementLocatorFactory(driver); MapFieldDecorator mfd = new MapFieldDecorator(melf); PageFactory.initElements(mfd, this); } private void enterAndSubmitLoginDetails() { //Conventional calls //usernameInput.sendKeys("user"); //passwordInput.sendKeys("password"); //Call to retrieve element from map loginui.get("usernameInput").sendKeys("user"); loginui.get("passwordInput").sendKeys("password"); } } 

MapAnnotations

 public class MapAnnotations extends Annotations { public MapAnnotations(Field field) { super(field); } public By buildBy() { if (getField().getAnnotation(MultipleFind.class) != null) return null; return super.buildBy(); } public Map buildMapBys() { Map details = null; Optional annot = Arrays.asList(getField().getAnnotations()) .stream() .filter(a -> a.annotationType().equals(MultipleFind.class)) .findAny(); if(annot.isPresent()) { details = createLocatorDetails(annot.get()); } return details; } private Map createLocatorDetails(Annotation annot) { String[] elemDets = ((MultipleFind) annot).elementDetails(); String delim = ((MultipleFind) annot).delimiter(); Map details = Arrays.stream(elemDets) .map(d -> d.split(delim)) .collect(Collectors.toMap(a -> a[0], a -> createBy(a[1], a[2]))); return details; } private By createBy(String howStr, String using) { How how = How.valueOf(howStr); switch (how) { case CLASS_NAME: return By.className(using); case CSS: return By.cssSelector(using); case ID: case UNSET: return By.id(using); case ID_OR_NAME: return new ByIdOrName(using); case LINK_TEXT: return By.linkText(using); case NAME: return By.name(using); case PARTIAL_LINK_TEXT: return By.partialLinkText(using); case TAG_NAME: return By.tagName(using); case XPATH: return By.xpath(using); default: // Note that this shouldn't happen (eg, the above matches all // possible values for the How enum) throw new IllegalArgumentException("Cannot determine how to locate element "); } } protected void assertValidAnnotations() { FindBys findBys = getField().getAnnotation(FindBys.class); FindAll findAll = getField().getAnnotation(FindAll.class); FindBy findBy = getField().getAnnotation(FindBy.class); MultipleFind multFind = getField().getAnnotation(MultipleFind.class); if (multFind != null && (findBys != null || findAll != null || findBy != null)) { throw new IllegalArgumentException( "If you use a '@MultipleFind' annotation, " + "you must not also use a '@FindBy' or '@FindBys' or '@FindAll' annotation"); } super.assertValidAnnotations(); } } 

MapElementLocatorFactory

 public class MapElementLocatorFactory implements ElementLocatorFactory { private final SearchContext searchContext; public MapElementLocatorFactory(SearchContext searchContext) { this.searchContext = searchContext; } public MapElementLocator createLocator(Field field) { return new MapElementLocator(searchContext, field); } } 

MapElementLocator

 public class MapElementLocator extends DefaultElementLocator { private Map elementBys; private SearchContext searchContext; public MapElementLocator(SearchContext searchContext, Field field) { this(searchContext, new MapAnnotations(field)); } public MapElementLocator(SearchContext searchContext,MapAnnotations annotations) { super(searchContext, annotations); this.elementBys = annotations.buildMapBys(); this.searchContext = searchContext; } public WebElement findElement(String elementName) { By by = elementBys.get(elementName); return searchContext.findElement(by); } } 

MapFieldDecorator

 public class MapFieldDecorator extends DefaultFieldDecorator { public MapFieldDecorator(ElementLocatorFactory factory) { super(factory); } public Object decorate(ClassLoader loader, Field field) { if (Map.class.isAssignableFrom(field.getType())) { MapElementLocator locator = (MapElementLocator) factory.createLocator(field); return proxyForMapLocator(loader, locator); } return super.decorate(loader, field); } @SuppressWarnings("unchecked") protected Map proxyForMapLocator(ClassLoader loader, MapElementLocator locator) { InvocationHandler handler = new LocatingMapElementHandler(locator); Map proxy; proxy = (Map) Proxy.newProxyInstance(loader, new Class[] { Map.class }, handler); return proxy; } } 

LocatingMapElementHandler

 public class LocatingMapElementHandler implements InvocationHandler { private final MapElementLocator locator; public LocatingMapElementHandler(MapElementLocator locator) { this.locator = locator; } public Object invoke(Object object, Method method, Object[] objects) throws Throwable { if(method.getName() != "get") throw new UnsupportedOperationException("Only get method of Map is supported for this proxy."); return locator.findElement((String)objects[0]); } } 

这仅适用于单个WebElement而不是List。 您可以尝试实现它,但问题是擦除会删除通用信息,因此如果您想要单个或多个元素,则无法正确确定。 只有get()方法可以在Map代理上工作,其他人会抛出UnSupportedException。