如何在Selenium C#中使用PageFactory / FindsBy初始化SelectElements?

时间:2015-07-24 14:57:33

标签: c# selenium drop-down-menu selenium-webdriver pageobjects

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

很遗憾,我发现FindsByAttribute不会初始化SelectElement(HTML <select>代码/下拉菜单)。到目前为止,我已经碰巧或提出了一些想法来解决它,但它们都不是理想的:

  1. PageFactoryFindsByAttributesealed,所以我不能仅通过继承它来强迫它。
  2. 在每种方法中从SelectElement手动实例化IWebElement是相当混乱和重复的。它也忽略了PageFactory中明显的内置等待并抛出NoSuchElementException s,除非我每次都添加一个等待 - 这需要在整个地方重复定位器,击败(部分)POM的目的。
  3. 使用IWebElement属性包装每个SelectElement属性不那么混乱,但仍然存在与上述相同的等待问题。
  4. 到目前为止,最好的选择是#3,并为SelectElement编写一个包装器,只是为每个方法添加一个等待。虽然这个解决方案将工作,但它会大量增加每个页面的代码,而不是这个(假设的)漂亮的代码:

    [FindsBy(How = How.Id, Using = "MonthDropdown")]
    public SelectElement MonthDropdown;
    

    我坚持使用包装器封装(我宁愿避免使用),并且:

    [FindsBy(How = How.Id, Using = "MonthDropdown")]
    private IWebElement _monthDropdown;
    public Selector MonthDropdown
    {
        get { return new Selector(MonthDropdown, Wait); }
    }
    

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

    有更好的方法吗?

    编辑:瞌睡错误的访问修饰符。固定。谢谢,@ JimEvans。

1 个答案:

答案 0 :(得分:14)

首先,.NET PageFactory实现中没有“内置等待”。您可以在InitElements的调用中轻松指定一个(稍后详细介绍)。目前,最适合您的选择是您的选择3,但我不会公开IWebElement成员;我将它private,因为PageFactory可以像公共成员一样简单地枚举私人成员。所以你的页面对象看起来像这样:

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

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

.NET绑定的最新版本重新构建了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对象。否则,你所实现的只是一个“页面包装器”,这是一种非常有效的方法,而不是人们称之为“页面对象”。