4

我有这么一个微不足道的问题,但我很难让我的代码在继续之前正确等待一个对象。

我为我的驱动程序设置了以下配置

session.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(60);

我期望这意味着它会等待至少 60 秒,然后再抛出与元素识别相关的错误,例如

Message: System.InvalidOperationException : An element could not be located on the page using the given search parameters.

然而,这种情况并非如此。尝试调用以下命令时,我在大约 2 秒内收到错误消息。

WindowsElement btn = session.FindElementByXPath("//Button[@Name='NEXT']");
btn.Click();

错误出现在我只是定义按钮属性的行上,而不是实际的 Click() 方法上。我没有正确传递元素属性吗?为什么按钮的实例化也会搜索它?

4

2 回答 2

4

winappdriver github上有一个未解决的问题。看看这个关于它的评论。这似乎是一个 Appium 问题。我不知道这个问题的状态。

基本上,这意味着您将不得不求助于解决方法。使用Thread.Sleep(/*milliseconds*/)是个坏主意

while在函数中实现了一个循环,以通过自动化 ID 获得控制,如下所示:

    /// <summary>
    /// Gets a UI element based on a AutomationId.
    /// </summary>
    /// <param name="automationId">The AutomationId is a unique value that can be found with UI inspector tools.</param>
    /// <param name="controlName">The name of the UI element.</param>
    /// <param name="timeOut">TimeOut in milliseconds</param>
    /// <returns></returns>
    protected WindowsElement GetElement(string automationId, string controlName, int timeOut = 10000)
    {
        bool iterate = true;
        WindowsElement control = null;
        _elementTimeOut = TimeSpan.FromMilliseconds(timeOut);
        timer.Start();

        while (timer.Elapsed <= _elementTimeOut && iterate == true)
        {
            try
            {
                control = Driver.FindElementByAccessibilityId(automationId);
                iterate = false;
            }
            catch (WebDriverException ex)
            {
                LogSearchError(ex, automationId, controlName);
            }
        }

        timer.Stop();
        Assert.IsFalse(timer.Elapsed > _elementTimeOut, "Timeout Elapsed, element not found.");
        timer.Reset();

        return control;
    }

与 相比,使用循环具有一些优势Thread.Sleep(),它更灵活,并且您有更多的选择,而不仅仅是阻止代码执行。

几个优点:

  • 您的测试脚本继续执行:想象您的脚本暂停 5 秒钟,而被测应用程序继续运行。在您的脚本可能想知道的那 5 秒内可能会发生很多事情。但它不能,因为如果你使用'Thread.Sleep()',代码执行会被阻塞。
  • 动态等待:while 循环将迭代直到满足条件。这使您的脚本在满足此条件后立即继续测试,从而使您的脚本运行得更快。例如,您正在等待页面加载。Thread.Sleep(5000)假设可以继续,而循环知道可以继续测试。
  • 使用计时器/超时组合,您可以检查操作花费了多长时间(例如保存一些编辑),如果花费的时间超过超时,您就知道不能继续了。

或者,此代码也可以正常工作:

protected WindowsElement GetElement(string automationId, string propertyName, int timeOut = 10000)
{
    WindowsElement element = null;
    var wait = new DefaultWait<WindowsDriver<WindowsElement>>(Driver)
    {
        Timeout = TimeSpan.FromMilliseconds(timeOut),
        Message = $"Element with automationId \"{automationId}\" not found."
    };

    wait.IgnoreExceptionTypes(typeof(WebDriverException));

    try
    {
        wait.Until(Driver =>
        {
            element = Driver.FindElementByAccessibilityId(automationId);

            return element != null;
        });
    }
    catch(WebDriverTimeoutException ex)
    {
        LogSearchError(ex, automationId, propertyName);
        Assert.Fail(ex.Message);
    }

    return element;
}

上面的代码只会抛出 aWebDriverTimeoutException而不是连续抛出NoSuchElementException。它不使用 while 循环,但我怀疑wait.Until(...)正在做类似的事情,因为 WinAppDriver 每 500 毫秒轮询一次 gui(请参阅对象PollingInterval上的DefaultWait属性。

于 2019-05-14T07:13:08.117 回答
0

我希望这有帮助:

public void WaitTillControlToDisplay(WindowsElement control , int Waittime=30)
{
    int startTime = 0;

    while (startTime < Waittime)
    {
        try
        {
            if (!control.Displayed)
                startTime += 1;
            else
            {
                Thread.Sleep(1000);
                return;
            }
        }
        catch (OpenQA.Selenium.WebDriverException)
        {
            Thread.Sleep(1000);
            return; // We should have Control loaded by now
        }

         Thread.Sleep(1000);
    }

    Assert.Fail("Time Out : Control - "+control+" Did not loaded within "+Waittime+" Seconds");

}

这里control应该在将其传递给方法之前进行标识。有时控件将位于另一个容器中,因此最好识别它并将其传递给方法。

于 2020-05-06T05:32:43.067 回答