页面模板上的Selenium回归测试可能会也可能不会打开

时间:2018-02-19 13:25:32

标签: java selenium-webdriver pageobjects serenity-bdd

我们的开发团队正在开发新的页面模板,其中包括对这些页面上定位器的大量更改。这些新页面位于切换位置,因此它们可能会在我们的测试环境中随时出现,也可能不会出现,具体取决于它们是打开还是关闭。 标头中有一个id,我可以用它来识别是否切换了新的页面模板。 任何人都可以告诉我处理这个问题的最佳方法。理想情况下,我想将新的定位器添加到相关的页面对象中,而不是将它们放在属性文件中。

当前定位器和WebElement:

@FindBy(className = "add-to-cart-btn")
    WebElementFacade addToCartBtn;

新模板上的新定位器:

className = "quickOrderSubmit"

1 个答案:

答案 0 :(得分:0)

找出一种方法,通过使用自定义ElementLocatorFactory, ElementLocator and Annotations类将旧定位器和新定位器保持在同一位置。这些将很容易地适应页面对象模型。它使用了FindBy注释的usinglocator value (id,class,css,xpath etc)字段的组合。这是FindBy使用的黑客攻击。一个新的注释会更好,但这是太多的工作。

这将通过在pageobject类的构造函数中使用以下代码集成到PageFactory initElements方法中。

OldNewElementLocatorFactory onelf = new OldNewElementLocatorFactory(driver);
PageFactory.initElements(onelf, this);

用法 -

  • 旧的和新的相同定位器策略。例如ID已更改。

@FindBy(使用=" id @@ id",id =" newid @@ oldid")或@FindBy(使用=&#34 ;名称@@ name",name =" newname @@ oldname")

使用部分 - 分隔符前面的第一部分是定位器的定位器策略,第二部分是定位器。

ID部分 - 第一部分是定位器策略的值,第二部分是的值。

  • 旧的和新的不同定位器策略。例如,ID现已更改为名称。

@FindBy(使用="名称@@ id",名称="新名称",id =" oldid")或@FindBy(使用=" xpath @@ css",xpath =" // div / input [@id =' comboid2']",css =&# 34; div输入[id =' comboid2']")

使用部分 - 与上述相同。

名称部分 - 新名称策略的定位器值。

ID部分 - 旧ID策略的定位器值。

  • 同样适用于与List类型变量一起使用的FindBy

@FindBy(使用="类@@ tag",className =" newClass",tagName ="输入") 私人清单输入;

@FindBy(使用="类@@ class",className =" newClass @@ oldClass") private List sameInputs;

  • 允许使用FindBy注释的标准格式。无需更改。 @FindBy(how = How.ID,使用=" origid")或@FindBy(id =" origid")

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

}

缺点 -

  1. 检查新注释用法格式的错误并不多。你可以看看它是否健壮。

  2. 它不会同时处理旧定位器和新定位器的FindBys和FindAll注释。它可能很容易,但Selenium源有一些私有方法,这使得很难通过继承来覆盖。您可以考虑采用不同的方法来解决它。虽然几乎没有看到这些注释使用过。