捕获调用元素时的异常,然后重试(页面工厂)。

huangapple go评论125阅读模式
英文:

catch exception when calling an element and try again (page factory)

问题

我在我的Selenium项目中使用页面工厂(Page Factory)和AjaxElementLocatorFactory。每个组件对象都扩展了这个类:

public abstract class AbstractComponent {

    public AbstractComponent(WebDriver driver){
        AjaxElementLocatorFactory factory = new AjaxElementLocatorFactory(driver, 5);
        PageFactory.initElements(factory, this);
    }
}

为了使我的测试更稳定,我希望在每次调用页面工厂中的元素时都实现try和catch,这样如果Selenium抛出任何类型的异常(比如StaleElementReferenceException或ElementNotInteractableException),它会在几秒钟内尝试再次操作。

我希望实现类似下面这样的内容(带有超时):

while(true) {
    try {
        this.element.click();
        break;
    }
    catch(Exception e) {
        throw e;
    }
}

我需要一个通用的解决方案,每次在页面工厂中使用元素时都能起作用。有什么建议吗?

英文:

I'm using a page factory and AjaxElementLocatorFactory in my selenium project. Each component object extends this class:

public abstract class AbstractComponent {

    public AbstractComponent(WebDriver driver){
        AjaxElementLocatorFactory factory = new AjaxElementLocatorFactory(driver, 5);
        PageFactory.initElements(factory, this);
    }
}

In order to make my tests more stable, I want to implement try and catch Each time I call an element in page factory, so if selenium throws an exception of any kind (like StaleElementReferenceException or ElementNotInteractableException), it will try again for a few seconds.

I'm looking to implement something like this (with timeout):

while(true) {
        try {
            this.element.click();
            break;
        }
        catch(Exception e) {
            throw e;
        }
    }

I need a general solution that will work each time I use an element in the page factory. Any suggestions?

答案1

得分: 2

你应该使你的工厂返回扩展的AjaxElementLocator,其中你会覆盖protected boolean isElementUsable(WebElement element)方法,默认情况下返回true

除非条件不成立,否则定位器将尝试新的查找元素的方法。因此,在你的页面类中不需要额外的代码。

异常被捕获并在AjaxElementLocator内部重新尝试。这基本上是它与常规定位器的不同之处。

你可以在这里找到一些细节。

基本上,上述内容应该足以使你的代码稳定,因为为了使你的测试稳定,你应该理解哪些条件定义了UI准备好进行测试。

但是,如果你需要添加一些重试功能(但请注意,陈旧的元素永远不会恢复到正常状态),你需要对以下结构进行一些更改:

  1. 扩展DefaultFieldDecorator类。有一个protected方法proxyForLocator,它定义了为你的字段创建代理对象的逻辑。在默认实现中,有一行InvocationHandler handler = new LocatingElementHandler(locator);,其中new LocatingElementHandler(locator);负责处理对页面字段的调用并将其分派到真实对象。
  2. 扩展LocatingElementHandler,使其调用父方法,但在需要时进行try-catch和重试。
  3. DefaultFieldDecorator的重写方法中,将旧的处理程序更改为你自定义的处理程序。
  4. 当你初始化你的页面时,使用以下代码:
public YourPageClass(SearchContext context) {
    PageFactory.initElements(
            new CustomFieldDecorator(
                    new AjaxElementLocatorFactory(context)
            ), this
    );
}

上述方法将允许你更改一个地方(实际上是两个地方:字段装饰器和调用处理程序),但涵盖了在与已定位元素交互时可能出现的所有可能异常。

英文:

You should make your factory return extended AjaxElementLocator where you override protected boolean isElementUsable(WebElement element) which returns true by default.

Unless the condition is not true the locator will be taking new attempts to lookup element. So no extra code in your page class will be required.

The exceptions are caught and re-tried inside AjaxElementLocator. This is basically how it is different from a regular locator.

You can find some details here.

Basically the above should be enough to make your code stable since in order to make your test stable you should understand which conditions define the UI ready for taking the test.

However if you need to add some retry functionality (but note that stale element won't ever get back to a normal state) you need to add some changes to the following structure:

  1. Extend DefaultFieldDecorator class. There is protected method proxyForLocator which defines the logic of creating a proxy pbject for your field. In that default implementation there is the line InvocationHandler handler = new LocatingElementHandler(locator); where new LocatingElementHandler(locator); is responsible for handling calls to page field and dispatching it to a real object.
  2. Extend LocatingElementHandler so that it calls a super method but try-catch and reties if needed.
  3. In overridden method of DefaultFieldDecorator change old handler to your custom one.
  4. When you initialize your page use the code like this:
public YourPageClass(SearchContext context) {
    PageFactory.initElements(
            new CustomFieldDecorator(
                    new AjaxElementLocatorFactory(context)
            ), this
    );
}

The approach above would let you to change one place (actually two: Field Decorator and Invocation Handler) but cover all possible exception which can appear when acting with already located element.

huangapple
  • 本文由 发表于 2020年8月31日 16:38:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/63667477.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定