我可以在具有数组或哈希图的页面对象模型中组织对象吗? [英] Can I organize objects in page object model with arrays or hash maps?

查看:72
本文介绍了我可以在具有数组或哈希图的页面对象模型中组织对象吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Selenium自动化的新手.而且我对Java有一定的了解.

I'm new to Selenium automation. And I have fair knowledge in java.

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

I have created test script to use for user registration.

我为此使用了页面对象模型.这是我的页面对象脚本.

I have used page object model for this. This is my page object script.

这就是我使用的

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个对象. 我该如何组织它以便长期使用?

I have about 100 objects to add like this. How can I organize this for long term use?

除了重复@Find by和WebElement之外,还有什么方法可以使用?

Is there a way to use than repeat the @Find by and WebElement?

我一直在寻找数组和哈希图.但是我不知道如何使用它.

I have looked for arrays and hash maps. But I have no idea how to use it.

我可以为此使用二维数组或哈希图吗?如果可以,怎么办?

Can I use a two dimensional array or hash map for this? If so how?

谢谢.

我想要这样的东西. 是否有可能?

I want something like this to use. Is it possible?

是否可以通过某种方式使用与以下内容相似的内容:

以下代码有问题.

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();
}

}

推荐答案

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

You will need to create custom annotation, elementfactory and decorator to accomplish this. Add the appropriate imports in the code below.

注释

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface MultipleFind {

    String delimiter() default "@@";
    String[] elementDetails();
}

示例PageObject - usernameInput @@ ID @@ username -第一部分将用作在地图上. second part定位器策略,它将与How.java enum中的值相对应. 第三部分定位符.此pageobject可以包含标准注释,例如FindBy等,以及自定义注释.

Sample PageObject - usernameInput@@ID@@username - The first part will be used as key in the Map. The second part is the locator strategy, this will correspond to the values in How.java enum. The third part is the locator. This pageobject can contain standard annotations like FindBy etc along with the custom annotation.

public class LoginPageObject extends BasePageObject<LoginPageObject> {

    //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<String, WebElement> 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");
    }       
}

地图注释-

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<String, By> buildMapBys() {
        Map<String, By> details = null;
        Optional<Annotation> 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<String, By> createLocatorDetails(Annotation annot) {
        String[] elemDets = ((MultipleFind) annot).elementDetails();
        String delim = ((MultipleFind) annot).delimiter();
        Map<String, By> 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<String, By> 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<String, WebElement> proxyForMapLocator(ClassLoader loader,
            MapElementLocator locator) {
        InvocationHandler handler = new LocatingMapElementHandler(locator);
        Map<String, WebElement> proxy;
        proxy = (Map<String, WebElement>) 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()方法可在地图代理上使用,其他方法将抛出UnSupportedException.

This will only work with individual WebElement not List. You can try to implement it, though the problem is erasure removes generic information so impossible to determine correctly if you want single or multiple elements. Only get() method will work on the Map proxy, others will throw UnSupportedException.

这篇关于我可以在具有数组或哈希图的页面对象模型中组织对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆