我正在使用PageFactory在Selenium WebDriver for C#中构建页面对象模型。

不幸的是,我发现FindsByAttribute不会初始化SelectElement(HTML <select>标签/下拉菜单)。到目前为止,我已经遇到或想出了一些解决方案,但没有一个是理想的:

  • PageFactoryFindsByAttributesealed,因此我不能仅通过继承它们来强制使用。
  • 在每种方法中,从SelectElement手动实例化IWebElement相当麻烦且具有重复性。除非我每次都添加一个等待,否则它还会忽略PageFactory中明显的内置等待并抛出NoSuchElementException,这将需要在各处重复定位器,从而破坏了POM的(部分)用途。
  • IWebElement属性包装每个SelectElement属性虽然不太麻烦,但是仍然存在与上面相同的等待问题。

  • 到目前为止,最好的选择是#3,然后为SelectElement编写一个包装程序,这只会增加每个方法的等待时间。尽管此解决方案可以工作,但它会大量堆积每个页面的代码,而不是下面的(假设的)漂亮代码:
    [FindsBy(How = How.Id, Using = "MonthDropdown")]
    public SelectElement MonthDropdown;
    

    我被 wrapper 包裹住了(我宁愿避免),并且:
    [FindsBy(How = How.Id, Using = "MonthDropdown")]
    private IWebElement _monthDropdown;
    public Selector MonthDropdown
    {
        get { return new Selector(MonthDropdown, Wait); }
    }
    

    由于SelectorSelectElement包装器,因此还必须接受IWait<IWebDriver>,以便它可以等待,并在每次访问它时实例化一个新的Selector

    有更好的方法吗?

    编辑:悄悄地放入了错误的访问修饰符。固定的。谢谢@JimEvans。

    最佳答案

    首先,.NET PageFactory实现中没有“内置等待”。您可以在对InitElements的调用中轻松指定一个(稍后详细介绍)。目前,最适合您的选择是您的选择3,尽管我不会公开IWebElement成员。我将其命名为private,因为PageFactory可以像枚举公共(public)成员一样轻松枚举私有(private)成员。因此您的页面对象将如下所示:

    [FindsBy(How = How.Id, Using = "MonthDropdown")]
    private IWebElement dropDown;
    public SelectElement MonthDropdownElement
    {
        get { return new SelectElement(dropdown); }
    }
    

    在需要时如何获取实际的IWebElement?由于SelectElement实现IWrappedElement,如果需要访问WrappedElement接口(interface)提供的元素的方法和属性,则可以简单地调用IWebElement属性。

    .NET绑定(bind)的最新版本已将PageFactory重组为更具扩展性。要添加所需的“内置等待”,可以执行以下操作:
    // Assumes you have a page object of type MyPage.
    // Note the default timeout for RetryingElementLocator is
    // 5 seconds, if unspecified.
    // The generic version of this code looks like this:
    // MyPage page = PageFactory.InitElements<MyPage>(new RetryingElementLocator(driver), TimeSpan.FromSeconds(10));
    MyPage page = new MyPage();
    PageFactory.InitElements(page, new RetryingElementLocator(driver, TimeSpan.FromSeconds(10)));
    

    此外,如果您确实需要自定义事物的工作方式,那么始终欢迎实现IPageObjectMemberDecorator,它使您可以完全自定义枚举属性的方式以及将值设置为用这些属性修饰的属性或字段的方式。 PageFactory.InitElements的(非通用)重载之一采用实现IPageObjectMemberDecorator的对象的实例。

    我将撇开严格定义的页面对象模式的正确实现,不要在每个页面对象之外公开任何WebDriver对象。否则,您所实现的只是一个“页面包装器”,这是一种完全有效的方法,而不是所谓的“页面对象”。

    09-28 07:35