我正在使用 PageFactory 在用于 C# 的 Selenium WebDriver 中构建页面对象模型。
不幸的是,我发现 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 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
,如果您需要访问 提供的元素的方法和属性,您可以简单地调用
接口(interface)。WrappedElement
属性>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 对象。否则,您要实现的只是一个“页面包装器”,这是一种完全有效的方法,而不是所谓的“页面对象”。
关于c# - 在 Selenium C# 中使用 PageFactory/FindsBy 时如何初始化 SelectElements?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31613763/