C# 通过定位器获取PageFactory IWebElement

C# 通过定位器获取PageFactory IWebElement,c#,webdriver,selenium-webdriver,C#,Webdriver,Selenium Webdriver,我有一种情况,我想获得用于查找元素的“By”定位器。我使用页面工厂初始化了元素 大概是这样的: [TestClass] public class Page { private IWebDriver _driver; [FindsBy(How = How.Id, Using = "Username")] public IWebElement TxtUsername { get; set; } public Page(IWebDriver driver)

我有一种情况,我想获得用于查找元素的“By”定位器。我使用页面工厂初始化了元素

大概是这样的:

[TestClass]
public class Page
{
    private IWebDriver _driver;

    [FindsBy(How = How.Id, Using = "Username")]
    public IWebElement TxtUsername { get; set; }

    public Page(IWebDriver driver)
    {
        _driver = driver;
        PageFactory.InitElements(_driver, this);
    }

    public void DoSomething()
    {
        By locator = GetLocator(TxtUsername); //Not real function
        IWebElement e = _driver.FindElement(locator);
    }
}
我知道我可以从GetAttribute中获取Id,但如果我使用XPath定位元素或者元素没有Id,则无法解决此问题

像这样:

By locator = By.Id(element.GetAttribute("id"));

谢谢

这是不可能的,因为从来没有任何关于您如何找到该元素的参考资料。当您调用
.FindElement
时,它只对查找元素并返回它感兴趣,而对记住如何找到它并不感兴趣

唯一的解决办法是自己保存一个引用,方法是创建一个类来记录它

比如:

public class SeleniumElement : IWrapsElement
{
    private IWebElement cachedElement;

    private By mechanismUsed;

    public SeleniumElement(IWebElement element, By locatorUsed)
    {
        mechanismUsed = locatorUsed;
        cachedElement = element;
    }

    public IWebElement WrappedElement
    {
        get
        {
            return cachedElement;
        }
    }
}

这是不可能的,因为从来没有任何关于您如何找到该元素的引用。当您调用
.FindElement
时,它只对查找元素并返回它感兴趣,而对记住如何找到它并不感兴趣

唯一的解决办法是自己保存一个引用,方法是创建一个类来记录它

比如:

public class SeleniumElement : IWrapsElement
{
    private IWebElement cachedElement;

    private By mechanismUsed;

    public SeleniumElement(IWebElement element, By locatorUsed)
    {
        mechanismUsed = locatorUsed;
        cachedElement = element;
    }

    public IWebElement WrappedElement
    {
        get
        {
            return cachedElement;
        }
    }
}

谢谢你的回复,但我还是设法使用反射来做我想做的事情

下面是我在C#中的实现:

GetLocator私有的(IWebElement元素) { //检索与字段对应的FieldInfo实例 FieldInfo field=element.GetType().GetField(“bys”,BindingFlags.Instance | BindingFlags.NonPublic); //检索字段的值,并根据需要强制转换 返回((列表)字段.GetValue(元素))[0]; }
注意:此实现仅适用于使用PageFactory初始化的元素。

感谢您的回复,但我成功地使用反射实现了我想要的功能

下面是我在C#中的实现:

GetLocator私有的(IWebElement元素) { //检索与字段对应的FieldInfo实例 FieldInfo field=element.GetType().GetField(“bys”,BindingFlags.Instance | BindingFlags.NonPublic); //检索字段的值,并根据需要强制转换 返回((列表)字段.GetValue(元素))[0]; }
注意:此实现仅适用于使用PageFactory初始化的元素。

Arran是正确的-您可以基于定位器获取元素,但无法将元素转换为定位器。您好Arran,谢谢您的回答。请检查我下面的答案。Arran是正确的-您可以获得基于定位器的元素,但无法将元素转换为定位器。嗨Arran,谢谢您的回答。请检查我下面的答案。这不适用于ByChained功能,因为您可以通过许多不同的方式来定位元素。我也很惊讶这一切都能奏效。我的印象是,当您使用
PageFactory
(以及
FindsBy
属性)时,它只会保存
By
使用的
记录。这对常规
RemoteWebElement
或其子类不起作用。只有当您使用的是
页面工厂
,它才会起作用。经过进一步考虑,我不能放弃这个。你做了几件事,可能会让以后发现这个问题和你的答案的人感到困惑。您使用的字段不是所有当前.NET实现都使用的
RemoteWebDriver
类的成员,因此如果用户未使用
PageFactory
,此代码将引发异常。您还将其作为
IWebElement
接口上的扩展方法,这可能会进一步混淆问题。最后,即使将此代码与
PageFactory
一起使用,也不能保证获得用于查找元素的实际定位器。我测试了不使用PageFactory,它确实不起作用。我编辑了问题和答案,以澄清情况和解决方案(还删除了扩展方法)。感谢您的回复。这不适用于ByChained功能,因为您可以通过许多不同的方式来定位元素。我也很惊讶这一切都能奏效。我的印象是,当您使用
PageFactory
(以及
FindsBy
属性)时,它只会保存
By
使用的
记录。这对常规
RemoteWebElement
或其子类不起作用。只有当您使用的是
页面工厂
,它才会起作用。经过进一步考虑,我不能放弃这个。你做了几件事,可能会让以后发现这个问题和你的答案的人感到困惑。您使用的字段不是所有当前.NET实现都使用的
RemoteWebDriver
类的成员,因此如果用户未使用
PageFactory
,此代码将引发异常。您还将其作为
IWebElement
接口上的扩展方法,这可能会进一步混淆问题。最后,即使将此代码与
PageFactory
一起使用,也不能保证获得用于查找元素的实际定位器。我测试了不使用PageFactory,它确实不起作用。我编辑了问题和答案,以澄清情况和解决方案(还删除了扩展方法)。谢谢你的回复。