当前位置: 首页 > 知识库问答 >
问题:

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

饶元章
2023-03-14

我们的开发团队正在开发新的页面模板,其中包括对这些页面上的定位器的大量更改。这些新页面处于切换状态,因此在我们的测试环境中,它们可能随时存在,也可能不存在,这取决于它们是否被切换打开或关闭。标头中有一个id,我可以用它来标识新页面模板是否被切换。谁能告诉我处理这件事的最好方法。理想情况下,我希望将新的定位器添加到相关的页面对象,而不是将它们放在属性文件中。

当前定位器和Web元素:

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

新模板上的新定位器:

className = "quickOrderSubmit"

共有1个答案

水渊
2023-03-14

通过使用自定义的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