在Selenium C#中使用PageFactory / FindsBy时如何初始化SelectElements? [英] How to initialize SelectElements while using PageFactory / FindsBy in Selenium C#?

查看:613
本文介绍了在Selenium C#中使用PageFactory / FindsBy时如何初始化SelectElements?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



不幸的是,我发现 FindsByAttribute

我在C#的Selenium WebDriver中使用PageFactory来构建一个页面对象模型/ code>不会初始化 SelectElement (HTML < select> 标签/下拉菜单)。到目前为止,我已经发生了一些想法,但没有一个是理想的:


  1. PageFactory FindsByAttribute 密封,所以我不能强制通过继承这些。

  2. IWebElement 手动实例化 SelectElement 在每种方法中是相当凌乱和重复的。它也忽略了 PageFactory 中的明显内置等待,并抛出 NoSuchElementException ,除非我每次添加一个等待这将需要在整个地方重复定位器,击败(部分)POM的目的。

  3. 包装每个 IWebElement 属性与 SelectElement 属性不那么凌乱,但仍然有与上述相同的等待问题。

目前为止最好的选项是#3,并为 SelectElement 编写一个包装器,这只是为每个方法添加一个等待。虽然这个解决方案将会工作,但它将大量批量编写每个页面的代码,而不是这个(假设的)漂亮的代码:

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

我被一个包装纸包裹住了(我宁愿避免的东西),还有: p>

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

使用选择器作为 SelectElement 包装器,也必须使用 IWait< IWebDriver> ,以便它可以等待,并实例化新的选择器每次我访问它。



有更好的方法吗?



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

解决方案

首先,在.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 重组为更可扩展。要添加您希望的内置等待,您可以执行以下操作:

  //假设您有一个页面对象的类型MyPage。 
//注意RetryingElementLocator的默认超时是
// 5秒,如果未指定。
//该代码的通用版本如下所示:
// 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 的对象的实例。 p>

我将抛​​开严格定义的页面对象模式的正确实现,不应将任何WebDriver对象暴露在每个页面对象之外。否则,所有您正在实施的是一个页面包装器,这是一个完美有效的方法,而不是称之为页面对象。


I am building a Page Object Model in Selenium WebDriver for C#, using the PageFactory.

Unfortunately, I have discovered that the FindsByAttribute will not initialize a SelectElement (HTML <select> tag / dropdown menu). I've happened upon or come up with a few ideas to work around it so far, but none of them is ideal:

  1. PageFactory and FindsByAttribute are sealed, so I can't force it to by just inheriting those.
  2. Manually instantiating a SelectElement from an IWebElement in each method is rather messy and duplicative. It also ignores the apparent built-in wait in PageFactory and throws NoSuchElementExceptions unless I add a wait every time I do this -- which would require repeating the locator all over the place, defeating (part of) the purpose of the POM.
  3. Wrapping each IWebElement property with a SelectElement property is less messy, but still has the same waiting problem as above.

The best option so far is #3, and writing a wrapper for SelectElement that just adds a wait to every method. While this solution will work, it will bulk up the code of each page a lot, as instead of this (hypothetical) pretty code:

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

I'm stuck with a wrapper wrapper (something I'd rather avoid), and:

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

With Selector being the SelectElement wrapper, that also has to take in the IWait<IWebDriver> so it can wait, and instantiating a new Selector every time I access it.

Is there a better way of doing this?

EDIT: Sleepily put in wrong access modifiers. Fixed. Thanks, @JimEvans.

解决方案

First, there's no "built-in wait" in the .NET PageFactory implementation. You can easily specify one in the call to InitElements (more on that in a bit). At present, the best option for you would be your option 3, though I wouldn't expose the IWebElement member; I'd make it private, since the PageFactory can enumerate over private members just as easily as public ones. So your page object would look like this:

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

How do you get the actual IWebElement when you need it? Since SelectElement implements IWrappedElement, you can simply call the WrappedElement property if you need access to the methods and properties of the element provided by the IWebElement interface.

Recent versions of the .NET bindings have restructured the PageFactory to be more extensible. To add the "built-in wait" you desire, you could do the following:

// 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))); 

Additionally, if you really need to customize how things work, you're always welcome to implement IPageObjectMemberDecorator, which allows you to fully customize how attributes are enumerated and values set to the properties or fields decorated with those attributes. One of the (non-generic) overloads of PageFactory.InitElements takes an instance of an object implementing IPageObjectMemberDecorator.

I'll leave aside that proper implementations of the Page Object Pattern as strictly defined shouldn't expose any WebDriver objects outside of each page object. Otherwise, all you're implementing is a "page wrapper," which is a perfectly valid approach, just not what one would call a "page object."

这篇关于在Selenium C#中使用PageFactory / FindsBy时如何初始化SelectElements?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆