Specflow NoSuchElementException找不到By.XPath

时间:2015-12-25 15:36:17

标签: c# selenium webdriver bdd specflow

我重新安排了我的类文件和Webdriver变量,因此我可以使用Context Injection在步骤之间共享Webdriver变量。 在我使用SetupFixture,Setup和TearDown之前,这对于BDD是不正确的。现在使用BeforeAllTests,BeforeTestRun等尝试上下文注入。 使用XPATH的我的FindElement无法正常工作。在我开始重新安排课程文件之前,它曾经工作过 我收到了错误:

OpenQA.Selenium.NoSuchElementException : Could not find element by: By.XPath: .//*[@id='twotabsearchtextbox']

该行突出显示错误的位置:

Searchfield_XPATH.SendKeys(text);

XPath定位器定义为:

[FindsBy(How = How.XPath, Using = ".//*[@id='twotabsearchtextbox']")]
private IWebElement Searchfield_XPATH { get; set; }

我的代码段如下:

//class setup.cs:
namespace SearchTest.Setup
{
    [Binding]
    public class BeforeAllTests
    {
        private readonly IObjectContainer objectContainer;
        private static SeleniumContext seleniumContext;

        public BeforeAllTests(IObjectContainer container)
        {
            this.objectContainer = container;
        }

        [BeforeTestRun]
        public static void RunBeforeAllTests()
        {
            seleniumContext = new SeleniumContext();
            seleniumContext.driver.Navigate().GoToUrl("http://localhost:8080");
        }

        [BeforeScenario]
        public void RunBeforeScenario()
        {
            objectContainer.RegisterInstanceAs<SeleniumContext>(seleniumContext);
        }
    }
}

// Class SeleniumContext.cs
namespace SearchTest.WebDriver
{
    public class SeleniumContext
    {
        public IWebDriver driver { get; private set; } 

        public SeleniumContext() 
        { 
            //create the selenium context
            driver = new FirefoxDriver();
     }
    }
}

//Class HomePage.cs
namespace SearchTest.PageObjects
{
    [Binding]
    public class HomePage : PageObjectBase 
    {
        private SeleniumContext seleniumContext;
        //private IWebDriver driver{ get; set; }

        [FindsBy(How = How.XPath, Using = ".//TITLE")]
        public IWebElement Title{ get; set; }

        // search text field on the homepage
        //[FindsBy(How= How.Id, Using="twotabsearchtextbox")]
        //private IWebElement Searchfield_ID { get; set; }

        [FindsBy(How = How.XPath, Using = ".//*[@id='twotabsearchtextbox']")]
        private IWebElement Searchfield_XPATH { get; set; }

        [FindsBy(How = How.Id, Using = "nav-search-submit-text")]
        private IWebElement SearchButton { get; set; }

        [FindsBy(How = How.XPath, Using = ".//*[@id='nav-search']/form/div[2]/div/input")]
        private IWebElement searchButton_Xpath {get; set;}

//        public HomePage(IWebDriver driver)
        public HomePage(SeleniumContext seleniumContext) : base(seleniumContext)
        {
            //driver1 = new FirefoxDriver();
           //Console.Out.WriteLine(driver1.Title);
            //driver1.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5)); // Set implicit wait timeouts to 5 secs
            //PageFactory.InitElements(driver1, this);
            this.seleniumContext = seleniumContext;
            PageFactory.InitElements(seleniumContext.driver, this);
        }

    public void goToURL() {
        //driver = new FirefoxDriver();
        //driver1.Navigate().GoToUrl("http://localhost:8080");
    }

    public void EnterSearchText(String text)
        {
            Searchfield_XPATH.SendKeys(text);
        }

    public SearchResultsPage click_search_button() {
        searchButton_Xpath.Click();
        return new SearchResultsPage(seleniumContext);
    }

    }   
}

//Class PageObjectBase.cs
namespace SearchTest.PageObjects
{
    public class PageObjectBase
    {
        private SeleniumContext seleniumContext;
        //private IWebDriver Driver { get; set; }

        public PageObjectBase(SeleniumContext seleniumContext)
        {
            this.seleniumContext = seleniumContext;
            //Driver = driver;
            //Driver = new FirefoxDriver();
            //Console.Out.WriteLine("From base class Driver.title = " + Driver.Title);
            //if (Driver.Title != titleOfPage)
            //    throw new NoSuchWindowException("PageObjectBase: The Page Title doesnt match.");
        }
    }
}

//The HTML is:

<form class="nav-searchbar" role="search" name="site-search" method="GET" action="/s/ref=nb_sb_noss" accept-charset="utf-8">
    <div class="nav-left">
    <div class="nav-right">
    <div class="nav-fill">
    <div class="nav-search-field">
        <input id="twotabsearchtextbox" class="nav-input" type="text" tabindex="21" autocomplete="off" name="field-keywords" value=""/>
    </div>
    <div id="nav-iss-attach"/>
</div>
</form>

我该如何解决这个问题? 我是BDD的新手,如果您发现我的设置有任何问题,并想建议我如何改进它,请做。

由于添加了以下代码:

[BeforeScenario]
    public void RunBeforeScenario()
    {
        objectContainer.RegisterInstanceAs<SeleniumContext>(seleniumContext);
        // HERE INSTEAD
        seleniumContext.driver.Navigate().GoToUrl("http://localhost:8080");
    }

我得到的错误是:

System.ArguementNullException: Value cannot be Null. 

突出显示的行在此处:objectContainer.RegisterInstanceAs<SeleniumContext>(seleniumContext);

我的代码是:

public class BeforeAllTests
{
    private readonly IObjectContainer objectContainer;
    private static SeleniumContext seleniumContext;

    public BeforeAllTests(IObjectContainer container)
    {
        this.objectContainer = container;
    }

    //[BeforeTestRun]
   // public static void RunBeforeAllTests()
   // {
   //     seleniumContext = new SeleniumContext();
   //     seleniumContext.driver.Navigate().GoToUrl("http://localhost:8080");
   // }

    //[BeforeScenario]
    //public void RunBeforeScenario()
   // {
   //     objectContainer.RegisterInstanceAs<SeleniumContext>(seleniumContext);
   //}

    [BeforeScenario]
    public void RunBeforeScenario()
    {
        objectContainer.RegisterInstanceAs<SeleniumContext>(seleniumContext);
        // HERE INSTEAD
        seleniumContext.driver.Navigate().GoToUrl("http://localhost:8080");
    }
}

}

1 个答案:

答案 0 :(得分:1)

我猜你不想要这行

seleniumContext.driver.Navigate().GoToUrl("http://localhost:8080");

在您的方法中标记为[BeforeTestRun],因为在运行所有测试之前(而不是在每个测试之前),只导航一次到该URL。

在标记为[BeforeScenario]的方法中使用它可能更有意义,因为这会在每个场景执行之前导航到您的基本URL。这种情况更可能发生,因为情景不应相互依赖(因此,一种情况不应该依赖于导航到特定页面的另一种情况)。

[BeforeScenario]
public void RunBeforeScenario()
{
    objectContainer.RegisterInstanceAs<SeleniumContext>(seleniumContext);
    // HERE INSTEAD
    seleniumContext.driver.Navigate().GoToUrl("http://localhost:8080");
}

这可以解释为什么Selenium未能找到该特定元素,因为在运行步骤定义时它可能实际上不在正确的页面上。

编辑:

所以BeforeAllTests的最终代码是:

public class BeforeAllTests
{
    private readonly IObjectContainer objectContainer;
    private static SeleniumContext seleniumContext;

    public BeforeAllTests(IObjectContainer container)
    {
        this.objectContainer = container;
    }

    [BeforeTestRun]
    public static void RunBeforeAllTests()
    {
        seleniumContext = new SeleniumContext();
    }

    [BeforeScenario]
    public void RunBeforeScenario()
    {
        objectContainer.RegisterInstanceAs<SeleniumContext>(seleniumContext);
        seleniumContext.driver.Navigate().GoToUrl("http://localhost:8080");
    }
}