2010-11-05 132 views
14

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

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

这样,我们可以摆脱线的睡眠,并有测试通过更快当服务器响应速度更快,不会有这么多的测试失败,由于时间问题。

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

注意:“waitFor”的其他变体不是我正在寻找的。我们已经在点击和其他方面使用了这些功能。我正在寻找等待网络流量的东西。感谢所有的反馈,我会尝试一些建议,但我仍然接受其他想法。

谢谢。

回答

2

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

这就是我们最终做的。 (注意,如果你总是只使用像JQuery这样的单个框架,那么有更简单的方法来获得Ajax调用是否正在运行,因为我们有几个使用JQuery和一堆的页面使用GWT)

我创建了一个JavaScript文件,每个页面只在你正在测试时加载。 (我通过在我们的JSP模板中包含一个片段来做到这一点:如果测试查询字符串参数被传入为真,请设置一个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,但应该很容易弄清楚。

然后,我增加了一个功能,硒用户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时传入XMLHttpRequest对象。但在IE中不起作用,所以我正在寻找替代方案。如果有人知道更好的方式来做到这一点,所以它在IE和FF都有效,我很乐意听到它。

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

0

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

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

您propably想把它塞进一个功能。

4

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

1

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

window.document.body.style.cursor 

但是,我发现这不能可靠地工作,即有时测试进行得太早。我不确定原因,但怀疑当调用onstop时,更新DOM并不一定完全完成。为了减少不必要的延迟,您可以自己实施轮询,并且比硒更频繁地轮询轮询。

4

尝试此页面上描述的所有变化后,我们结束了这一战略:

注入一个特殊的JavaScript,基本上覆盖所有的相关框架的方法和保持计数器未完成的请求数的,在开始时递增并在完成时递减。由于JavaScript的异步特性,它不是而是足以保留一个布尔变量,您可能最终在自己的逻辑中出现竞争条件。

如果您使用的是视觉效果,您可能也希望为视觉效果做到这一点;变形/褪色等视觉效果会有同样的问题。

所以我们基本上做了一个常规的“点击”,然后总是等待这个计数器再次达到0,使用JavaScript很像其他人在这里所建议的。在我们完成这项工作后,我们将短暂问题减少到无。

请记住,硒不会从“点击”返回,直到所有同步onclick事件都被处理完毕,所以您必须确保让这些计数器增加为onclick的直接结果。

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

+0

对于我们内部构建的AJAX框架,我们做了同样的事情,在WaitForCondition()中调用IsTheCountZeroYet()函数。我明白你可以轻松地用jQuery来做到这一点。其他框架,也许也是。 – 2010-11-11 22:07:08

+0

有趣的是,prototype.js中的ajax计数器是越野车,它们并不总是返回0。视觉效果还没有这种类型的计数器。所以我们必须推出自己的。 – krosenvold 2010-11-13 19:21:57