【问题标题】:Locator object cannot be null with Selenium PageObjectsSelenium PageObjects 的定位器对象不能为空
【发布时间】:2018-12-01 04:02:18
【问题描述】:

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

我正在使用 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 : 定位器对象的 SearchContext 不能为空 参数名称:定位器

批处理类和 AddNewClient 类中的代码是相同的,所以我看不出是什么问题

批次:

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 代码移动到登录代码脚本中,它运行良好,但是当我将它推回自己的测试时,它又出错了。

在 cmets 中请求的完整堆栈跟踪。

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

【问题讨论】:

  • batch 类和AddNewClient 类中的代码是一样的,所以我看不出是什么问题 嗯,显然有问题。您需要添加完整的堆栈跟踪以及所有相关代码。
  • 我同意某些地方肯定存在问题。我已经添加了堆栈跟踪。我相信我已经掌握了所有的相关代码。剩下的只是元素和 selenium 命令
  • InitElements 元素初始化失败,元素相关。并且只发布方法签名可能永远不会有用。
  • 我已经把我的 RunTest 类的所有东西都放好了(除了结束 })那么你认为问题出在我的批处理类的某个地方吗?我只问它是否可以正常工作,如果我将调用它放入登录测试中。因此我完全困惑!如果您认为这会有所帮助,很高兴提出我所有的元素集(我很担心我会把它变成一个大问题!)
  • 元素在Batch类中,你可以在堆栈跟踪中看到异常是从Batch类构造函数中抛出的,那么是的,这个类是相关的。你应该添加所有的.

标签: c# selenium selenium-webdriver pageobjects


【解决方案1】:

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

定位器对象的SearchContext不能为空

来自githubInitElements方法

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

建议你把Login()移到[SetUp]注解下,加上[TearDown]。它将在每次测试之前和之后运行,并为您提供“干净的石板”

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();
        }
    }
}

编辑

如果您想为所有测试运行一次SetUpTearDown,您可以使用[TestFixtureSetUp][TestFixtureTearDown] 注释。你还需要在类中添加[TestFixture]

[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]

【讨论】:

  • 谢谢。它确实有效并解决了最初的问题,我想这是最佳实践方法。有什么方法可以在不为每次测试重做的情况下编写它?不幸的是,由于网站的编写方式(我无法控制)登录脚本每次需要 30 秒(它的 2 个按钮点击和正常的用户名和密码!)所以自然地为每个测试调用它会减慢这个过程非常糟糕。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-27
  • 1970-01-01
  • 2023-03-27
  • 2012-09-30
  • 1970-01-01
相关资源
最近更新 更多