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

Mar*_*erg 9 c# selenium pageobjects selenium-webdriver drop-down-menu

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

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

  1. PageFactoryFindsByAttributesealed的,所以我不能只继承那些它强制.
  2. 手动实例化SelectElement来自IWebElement在每个方法是相当混乱和重复的.它也忽略了明显的内置等待PageFactory和抛出NoSuchElementExceptions,除非我每次都添加一个等待 - 这需要在整个地方重复定位器,从而击败(部分)POM的目的.
  3. IWebElement属性包装每个属性SelectElement不那么混乱,但仍然具有与上面相同的等待问题.

到目前为止,最好的选择是#3,为此编写一个包装SelectElement只会为每个方法添加一个等待.虽然这个解决方案可行,但它会大量增加每个页面的代码,而不是这个(假设的)漂亮的代码:

[FindsBy(How = How.Id, Using = "MonthDropdown")]
public SelectElement MonthDropdown;
Run Code Online (Sandbox Code Playgroud)

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

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

随着Selector作为SelectElement包装,也必须采取的IWait<IWebDriver>,因此它可以等待,和一个新的实例Selector访问它的每一次.

有没有更好的方法呢?

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

Jim*_*ans 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); }
}
Run Code Online (Sandbox Code Playgroud)

如何IWebElement在需要时获得实际效果?从SelectElementimplements开始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))); 
Run Code Online (Sandbox Code Playgroud)

此外,如果您确实需要自定义工作方式,则始终欢迎您实施IPageObjectMemberDecorator,这样您就可以完全自定义枚举属性的方式,并将值设置为使用这些属性修饰的属性或字段.其中一个(非泛型)重载PageFactory.InitElements采用对象实现的实例IPageObjectMemberDecorator.

我将抛开严格定义的页面对象模式的正确实现不应该暴露每个页面对象之外的任何WebDriver对象.否则,你所实现的只是一个"页面包装器",这是一种非常有效的方法,而不是人们称之为"页面对象"的方法.

  • 谢谢!`RetryingElementLocator`确实让我不必包装`SelectElement`.我希望有一种方法可以获得更清洁的东西(比如`FindsBy`直接在'SelectElement`上),但我并不感到惊讶.不是说我现在一定需要它,但你还有关于使用`IPageObjectMemberDecorator`的更多信息吗?即使谷歌只有10个结果. (2认同)