Selenium - 等待网络流量

时间:2010-11-05 22:20:25

标签: java networking selenium

我们将Selenium与Java API和一些Javascript用户扩展一起使用。我们在应用程序中使用了大量的AJAX调用。我们的很多测试都是随机失败的,因为有时候AJAX调用比其他时候完成得慢,所以页面没有完全加载。我们通过等待特定元素或Thread.sleep来解决这个问题。我试图找到一种方法,而不是等待网络流量完成。这样我们就可以做到:

selenium.click("some JS button");
selenium.waitForNetwork();
assertTrue(something);

这样我们可以摆脱线程休眠,并且当服务器响应更快并且由于时序问题而没有那么多测试失败时,测试通过得更快。

我无法找到一种方法来搜索Google。有没有人有任何想法我们如何才能做到这一点? (最好是通过Javascript或Java API,但欢迎所有建议。)

注意:“waitFor”的其他变体不是我想要的。我们已经在点击和其他内容中使用了这些内容。我正在寻找等待NETWORK TRAFFIC的东西。感谢所有的反馈,我会尝试一些建议,但我仍然对其他想法持开放态度。

感谢。

6 个答案:

答案 0 :(得分:4)

Selenium中有几种类型的waitFor可用。在您的测试用例中,如果您知道页面加载时会出现特定文本,则可以使用waitForText。如果填充了不同的DOM元素(通过Ajax / pageload),您可以按顺序添加waitForText。

答案 1 :(得分:4)

在尝试了本页描述的所有变体后,我们最终采用了这一策略:

注入一个特殊的javascript,它基本上覆盖了所有相关的框架方法,并保留了未完成请求数的计数器,它在启动时递增,在完成时递减。由于javascript的异步性质,足以保留一个布尔变量,你可能会在自己的逻辑中结束竞争条件。

如果您正在使用视觉效果,您可能也希望为视觉效果执行此操作;变形/褪色和其他视觉效果会有同样的问题。

所以我们基本上做一个常规的“点击”然后总是等待这个计数器再次达到0,使用javascript就像其他人在这里建议的那样。在我们实现这一目标之后,我们将暂时性问题减少为无。

请记住,在处理完所有同步onclick事件之前,selenium不会从“click”返回,因此您必须确保将这些计数器增加为onclick的直接后果。

有关如何覆盖框架方法的说明,您需要查阅框架文档;我们在原型中使用addMethods。可以将此覆盖保留在运行测试时仅添加到页面的特殊JavaScript中。

答案 2 :(得分:2)

更新:我使用与Selenium2相同的方法(wrapRequest),它仍然有效。唯一的区别是我不使用用户扩展。我只是执行javascript来查询JSP加载的代码。

这是我们最终做的事情。 (注意,如果你总是只使用像JQuery这样的单个框架,那么如果运行Ajax调用有更简单的方法。我们不得不更多地使用jimmy-rig,因为我们有几个页面使用JQuery和一堆使用GWT)

我创建了一个Javascript文件,只有在您测试时才会加载每个页面。 (我通过在JSP的模板中包含一个片段来完成此操作:如果测试查询字符串param作为true传入,则设置一个cookie。如果设置了该cookie,则包含javascript文件) 这个javascript文件实际上包装XMLHttpRequest对象以保持所有发送请求的计数:

function wrapRequest(xmlRequest) {
    var oldSend = xmlRequest.prototype.send;
    xmlRequest.prototype.send = function() {
        var oldOnReady = this.onreadystatechange;
        oldOnReady = function() {
            oldOnReady.apply(this, arguments);
            // if call is complete, decrement counter.
        }
        // increment counter
        if(oldSend.apply)
            oldSend.apply(this, arguments);
        else if (oldOnReady.handleEvent) { //Firefox sometimes will need this
            oldOnReady.handleEvent.apply(this, arguments);
        }
    }
}

如果async == false,那还有一点,但这应该很容易理解。

然后我向selenium user-extensions.js添加了一个函数,它看起来像这样:

Selenium.prototype.getIsNetworkReady = function() {
    if(this.browserbot.topWindow.isNetworkReady) { //sometimes this method is called before the page has loaded the isNetworkReady function
        return this.browserbot.topWindow.isNetworkReady();
    }
    return false;
}

另外,请注意topWindow上的检查:这是因为在选择iframe时出现问题。

此外,您必须在每个加载的iFrame的XMLHttpRequest对象上调用wrapRequest方法。我现在使用:document.addEventListener("DOMNodeInserted", onElementAdded, true);执行此操作,然后在onElementAdded中,我只需在加载iframe时获取iframe并传入XMLHttpRequest对象。但这在IE中不起作用,所以我正在寻找替代方案。如果有人知道更好的方法,那么它适用于IE和FF我很乐意听到它。

无论如何,这是实施的要点。希望这有助于将来的任何人。

答案 3 :(得分:1)

我们已经有了客户端代码来在AJAX请求期间更改鼠标光标(使用带有a4j:statusonstart属性的onstop。因此我们可以简单地等待JavaScript表达式的值

window.document.body.style.cursor

但是,我发现这不能可靠地工作,即有时候测试过早进行。我不确定原因,但怀疑在调用onstop时不一定完全更新DOM。

至于减少不必要的延迟,你可以自己实施民意调查,并且比硒更频繁地进行民意调查。

答案 4 :(得分:1)

这可能不适合你,但由于类似的问题我们转移到Selenium 2(又名WebDriver)。我们将PageFactoryAjaxElementLocatorFactory

一起使用

为了使迁移更容易,有一个Selenium Emulation,计划是完全合并Selenium 1和WebDriver,这是Selenium 2的主要目标。

答案 5 :(得分:0)

是的,做这样的事情(Pseudocode):

int i = 0;
while (element is not yet present) {
  i++;
  if (i>TRESHOLD) {
    throw an exception
  }
  Thread.sleep(200);
}
//go on

您可能希望将其填充到函数中。