Selenium PageObjects 的定位器对象不能为 null

Locator object cannot be null with Selenium PageObjects

我确定这是一个简单的问题,但我无法找到此错误的原因,更不用说解决方案了。

我正在使用 selenium 页面对象,直到现在我将新页面添加到我的测试时,它一直 运行 完美。

这是我的主要代码

class RunTest
{
   static IWebDriver driver;

   [Test]
   public void Login()
   {
      var options = new ChromeOptions();
      options.AddArguments("chrome.switches", "--disable-extensions --disable-extensions-file-access-check --disable-extensions-http-throttling --disable-infobars --enable-automation ");
      options.AddUserProfilePreference("credentials_enable_service", false);
      options.AddUserProfilePreference("profile.password_manager_enabled", false);
      driver = new ChromeDriver(options);

      driver.Url = ConfigurationManager.AppSettings["URL"];

      driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(10);

      var loginPage = new LoginPage(driver);
      loginPage.LoginToApplication("Test1");

      IWait<IWebDriver> wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
      var element = wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//*[@id='content']/div/div/div/div/ul/li[4]/div[1]/div[2]/div/button[1]")));

      var setenv = new SetEnvironment(driver);
      setenv.SetEnvQA();
}

[Test]
public void AddBatchTest()
{
   var AddBatch = new Batch(driver);
   AddBatch.AddNewBatch("Test1");
}

[Test]
public void Test1()
{
   var NewCli = new AddNewClient(driver);
   NewCli.Addanewclient("Test1");
}

Login 和 Test1 测试(与其他测试一起)运行 完美,但是 Batch 测试因

而失败

System.ArgumentException : The SearchContext of the locator object cannot be null Parameter name: locator

批处理 class 和 AddNewClient class 中的代码相同,所以我看不出问题所在

批次:

namespace OnlineStore.PageObjects
{
    class Batch
    {
        IWebDriver driver;

        //Admin link in left hand otions
        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_NavigationPanel_navigationpanel1_hlAdmin']")]
        public IWebElement AdminScreen { get; set; }

        //Add new batch link
        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_HyperLink38']")]
        public IWebElement AddNewBatchLnk { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_DatepickerReceived_txtDate']")]
        public IWebElement DateReceived { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='aspnetForm']/div[3]/div/div[2]/div[3]/table[3]/tbody/tr/td/table/tbody/tr[7]/td]")]
        public IWebElement SelectToday { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_txtTotal']")]
        public IWebElement BatchTotal { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_ucCurrency_ddlCurrency']")]
        public IWebElement Currency { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_cboAgency']")]
        public IWebElement Provider { get; set; }

        [FindsBy(How = How.XPath, Using = "//*[@id='ctl00_MainBody_txtNote']")]
        public IWebElement BatchNotes { get; set; }

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

        public void AddNewBatch(string testName)
        {
            var userData = ExcelDataAccess.GetTestData(testName);

            IWait<IWebDriver> wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30.00));

            AdminScreen.Click();
            wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//*[@id='ctl00_MainBody_HyperLink38']")));

            AddNewBatchLnk.Click();
            wait.Until(ExpectedConditions.ElementIsVisible(By.XPath("//*[@id='ctl00_MainBody_DatepickerReceived_txtDate']")));

            DateReceived.SendKeys("22/05/2017");
            //SelectToday.Click();
            BatchTotal.SendKeys("1000");
            Currency.SendKeys("USD");
            Provider.SendKeys("Client");
            BatchNotes.SendKeys("Some Batchg notes here please");

        }
    }
}

添加新客户端:

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

public void Addanewclient(string testName)
{ 
   //Code here
}

有什么想法吗?

更新:我尝试将 AddBatchTest 代码移动到登录代码脚本中并且 运行 没问题,但是当我将它推回自己的测试时它再次出错。

评论中要求的完整堆栈跟踪。

Result StackTrace:  
at OpenQA.Selenium.Support.PageObjects.PageFactory.InitElements(Object page, IElementLocator locator, IPageObjectMemberDecorator decorator)
   at OpenQA.Selenium.Support.PageObjects.PageFactory.InitElements(ISearchContext driver, Object page)
   at OnlineStore.PageObjects.Batch..ctor(IWebDriver driver) in C:\Users\andrew.logan-smith\documents\visual studio 2015\Projects\OnlineStore\OnlineStore\PageObjects\Batch.cs:line 54
   at OnlineStore.TestCases.RunTest.AddBatchTest() in C:\Users\andrew.logan-smith\documents\visual studio 2015\Projects\OnlineStore\OnlineStore\TestCases\RunTest.cs:line 52
Result Message: 
System.ArgumentException : The SearchContext of the locator object cannot be null
Parameter name: locator

Test方法在RunTestclass中的顺序不一定是执行顺序。在您的情况下,顺序可能是 AddBatchTest() -> Login() -> Test1()。这导致 driver 在调用 Batch 构造函数时成为 null 并且 PageFactory.InitElements 接收 null 作为 driver 参数,即 SearchContext ,因此错误

The SearchContext of the locator object cannot be null

InitElements 方法来自 github

public static void InitElements(ISearchContext driver, object page)
{
    InitElements(page, new DefaultElementLocator(driver));
}

我建议您将Login()移到[SetUp]注解下并添加[TearDown]。它会在每次测试前后 运行 并为您提供 "clean slate"

public class RunTest
{
    private IWebDriver driver = null;

    [SetUp]
    public void Login()
    {
        driver = new ChromeDriver(options);
        //...
    }

    [Test]
    public void AddBatchTest()
    {
        var AddBatch = new Batch(driver);
        AddBatch.AddNewBatch("Test1");
    }

    [Test]
    public void Test1()
    {
        var NewCli = new AddNewClient(driver);
        NewCli.Addanewclient("Test1");
    }

    [TearDown]
    public void TearDown()
    {
        if (Driver != null)
        {
            Driver.Quit();
        }
    }
}

Edit

如果你想 运行 SetUpTearDown 一次性完成所有测试,你可以使用 [TestFixtureSetUp][TestFixtureTearDown] 注释。您还需要将 [TestFixture] 添加到 class

[TestFixture]
public class RunTest
{
    [TestFixtureSetUp]
    public void SetUp()
    {
    }

    [Test]
    public void AddBatchTest()
    {
    }

    [Test]
    public void Test1()
    {
    }

    [TestFixtureTearDown]
    public void TearDown()
    {
    }
}

*这是针对 NUnit 2,对于 NUnit 3 使用 [OneTimeSetUp][OneTimeTearDown].