如何使用 WatiN 处理动态填充的列表框

软件测试 瓦廷
2022-01-11 23:50:53

我正在寻找一些关于如何处理我在页面上使用两个控件时遇到的轻微时间问题的建议。我有一个最多包含 10 个项目的列表框,但是该框的内容可能会根据在搜索框中输入的字符而改变。

例如:我在搜索框中输入 zi,列表框将开始填充 Zimmerman...

我遇到的问题是在输入文本和使用 WatiN 单击按钮以将视图更改为列表中顶部项目的视图之间有足够的延迟。

所以这就是我目前在我的

            browser.Page<AVDashboardPage>().SearchBox.TypeText("zi");
            browser.Page<AVDashboardPage>().ChangeActBtn.Click();

我正在考虑做的是简单地在 AVDashboard 页面类中编写一个包含小延迟的小方法。

    public void EnterSearchTextWithDelay(string searchText)
    {
        SearchBox.TypeText(searchText);
        System.Threading.Thread.Sleep(200);

    }

我想我也可以通过添加一个在列表框中查找相应元素的while循环来做到这一点,但我担心这可能会很慢。


所以我的方法最终看起来像这样:

public void EnterSearchTextWithDelay(string searchText)
{
    SearchBox.TypeText(searchText);
    int counter = 0;
    while(!AccountList.Text.Contains(searchText) && counter < 50)
    {
        System.Threading.Thread.Sleep(10);
        counter++;
    }

}
4个回答

您应该检查列表框中的元素,而不是使用睡眠,您可能认为这是一种缓慢的方法,但您将获得更可靠的测试,从长远来看,这将节省您的时间。

只要确保你记得在循环中有一个超时,以防项目由于某种原因永远不存在。

睡眠应该在自动化测试中使用,因为它们会在给定的时间段内停止执行。在测试中帮助控制竞争条件或同步问题的更好的解决方案是使用类似于以下内容的轮询循环:

int pollCount = 0;
while (listbox_element_not_found && pollCount < maxPollCount) 
{
  System.Threading.Thread.Sleep(10);
  pollCount++;
}

当然,如果您的循环超时,您可能希望使用 if 语句进行分支并将测试标记为无法确定以进行调查。

我还建议不要在列表框中查找元素(尤其是因为列表项更改),如果在填充列表框时 ChangeActBtn 为“灰色”,您可以制作一个轮询循环来检测按钮控件何时更改其从 false 到 true 的启用属性(如果在填充列表时开发人员的按钮是灰色的)。

恕我直言,后一种方法使测试更加健壮,因为您不依赖于匹配列表框中的特定元素,并且还改进了设计,因为本质上它是“过早”单击按钮导致您的测试和测试之间出现同步问题AUT 所以这取决于按钮控件而不是列表框上的测试执行。

如果在键入文本时通过 AJAX 动态拉取列表,则可以实现 WaitForAsyncPostbackToComplete 以等待列表完全填充,然后再选择并单击按钮。

您可以查看以下博客文章,了解实现 WaitForAsyncPostbackToComplete 方法的代码。这会将您的等待时间减少到最低限度并确保代码的稳定性。

答案真的取决于动态负载的实现

如果您使用的是 jQuery,那么您可以从https://stackoverflow.com/questions/2375709/how-to-wait-for-jquery-ajax-requests-to-complete-from-watin实现类似的解决方案。

public static class BrowserExtensions
{
    public static void WaitForAjaxRequest( this Browser browser )
    {
        int timeWaitedInMilliseconds = 0;
        var maxWaitTimeInMilliseconds = Settings.WaitForCompleteTimeOut*1000;

        while ( browser.IsAjaxRequestInProgress()
                && timeWaitedInMilliseconds < maxWaitTimeInMilliseconds )
        {
            Thread.Sleep( Settings.SleepTime );
            timeWaitedInMilliseconds += Settings.SleepTime;
        }
    }

    public static bool IsAjaxRequestInProgress( this Browser browser )
    {
        var evalResult = browser.Eval( "watinAjaxMonitor.isRequestInProgress()" );
        return evalResult == "true";
    }

    public static void InjectAjaxMonitor( this Browser browser )
    {
        const string monitorScript =
            @"function AjaxMonitor(){"
            + "var ajaxRequestCount = 0;"

            + "$(document).ajaxStart(function(){"
            + "    ajaxRequestCount++;"
            + "});"

            + "$(document).ajaxComplete(function(){"
            + "    ajaxRequestCount--;"
            + "});"

            + "this.isRequestInProgress = function(){"
            + "    return (ajaxRequestCount > 0);"
            + "};"
            + "}"

            + "var watinAjaxMonitor = new AjaxMonitor();";

        browser.Eval( monitorScript );
    }
}

此解决方案适用于我基于此博客文章的 ajax 控制工具包。

            bool isInPostback = true;
            while (isInPostback)
            {

                // the exception is to handle if the page does not have the ajax control toolkit code ready and loaded
                try
                {
                    // This line of code calls javascript in browser to execute the ajax toolkit's
                    // get_isInAsyncPostBack method
                    isInPostback = Convert.ToBoolean(_ie.Eval("Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack();"));

                }
                catch (WatiN.Core.Exceptions.JavaScriptException e)
                {
                    if (e.Message == "TypeError: 'Sys' is undefined")
                    {
                        isInPostback = false;
                        break;
                    }
                    else
                    {
                        throw;
                    }
                }

                // This exception is being thrown when running under impersonation
                // I think the eval needs an impersonation call first
                catch (WatiN.Core.Exceptions.RunScriptException scriptException)
                {
                    Debug.Print(scriptException.Message);
                    isInPostback = false;
                }
                if (isInPostback)
                {
                    //sleep for 200ms and query again  
                    System.Threading.Thread.Sleep(200);
                }
            }
        }