我正在使用PageFactory在Selenium WebDriver for C#中构建页面对象模型。
不幸的是,我发现FindsByAttribute
不会初始化SelectElement
(HTML <select>
标签/下拉菜单)。到目前为止,我已经遇到或想出了一些解决方案,但没有一个是理想的:
PageFactory
和FindsByAttribute
是sealed
,因此我不能仅通过继承它们来强制使用。 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); }
}
由于
Selector
是SelectElement
包装器,因此还必须接受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对象。否则,您所实现的只是一个“页面包装器”,这是一种完全有效的方法,而不是所谓的“页面对象”。