使用Selenium或WebDriver测试GWT应用

对于Web应用程序开发人员及其团队而言,良好的功能测试是最困难的任务之一。 开发价格低廉且维护良好的测试是一项挑战,这有助于降低质量检查成本并提高质量。

Selenium和WebDriver(本质上现在是Selenium的继承者)都提供了一种无需人工就可以在多个目标环境中对Web应用程序进行功能测试的好方法。 过去,Web UI是使用页面导航构建的,以允许用户提交表单等。如今,越来越多的Web应用程序使用Ajax,因此其行为和外观与桌面应用程序非常相似。 但是,这给测试带来了问题– Selenium和WebDriver旨在与用户交互配合使用,从而导致页面导航,并且不能与现成的AJAX应用很好地配合使用。

基于GWT的应用程序尤其存在此问题,但是我发现有一些方法可以开发有用且有效的测试。 在模拟用户输入和查找DOM元素方面,GWT还提出了其他问题,我将在下面进行讨论。 请注意,我的代码示例使用Groovy使其简洁,但是可以很容易地将它们转换为Java代码。

问题1:处理异步更改

在测试基于GWT的应用程序时,开发人员很快就会面临的一个问题是检测并等待对用户交互的响应。 例如,用户可以单击导致AJAX调用的按钮,该调用将成功并关闭窗口,或者显示错误消息。 我们需要的是一种阻止方法,直到我们看到预期的变化,并且超时,这样,如果我们看不到预期的变化,我们可能会失败。

解决方案:使用WebDriverWait

最简单的方法是利用WebDriverWait(或Selenium的Wait)。 这使您可以等待条件,并在条件评估为true时继续进行。 下面,为了简洁地使用闭包,我使用了Groovy代码,但是在Java中也可以做到这一点,尽管由于需要匿名类,所以使用了更多代码。

def waitForCondition(Closure closure) {int timeout = 20WebDriverWait w = new WebDriverWait(driver, timeout)w.until({closure() // wait until this closure evaluates to true} as ExpectedCondition)
}def waitForElement(By finder) {waitForCondition {driver.findElements(finder).size() > 0;}
}def waitForElementRemoval(By finder) {waitForCondition {driver.findElements(finder).size() == 0;}
}// now some sample test code submitButton.click() // submit a form// wait for the expected error summary to show up
waitForElement(By.xpath("//div[@class='error-summary']"))
// maybe some more verification here to check the expected errors// ... correct error and resubmitsubmitButton.click()
waitForElementRemoval(By.xpath("//div[@class='error-summary']"))
waitForElementRemoval(By.id("windowId"))

从示例中可以看到,您的代码可以专注于实际的测试逻辑,同时无缝地处理GWT应用程序的异步特性。

问题2:在您对DOM几乎没有控制的情况下定位元素

在使用模板的Web应用程序(JSP,Velocity,JSF等)中,您可以很好地控制并轻松查看页面将具有的DOM结构。 对于GWT,情况并非总是如此。 通常,您正在处理无法精确控制的嵌套元素。

使用WebDriver和Selenium,可以使用几种方法来定位元素,但最有用的是DOM元素ID和XPath。 我们如何利用它们来获得可维护的测试,而这些测试不会因布局的微小变化而中断?

解决方案:结合使用XPath和ID来限制范围

以我的经验,要在WebDriver中开发功能性GWT测试,您应该使用稍微松散的XPath作为查找元素的主要方法,并在适用时通过DOM ID对这些调用进行作用域来对其进行补充。

特别是,请在应用程序中唯一的窗口或选项卡等顶级元素上使用ID,这些ID在页面中不会出现多次。 这些可以帮助确定您的XPath表达式的范围,该表达式可以查找窗口或表单标题,字段标签等。

以下是一些示例,可助您一臂之力。 请注意,我们在XPath中使用//和*来保持表达式的灵活性,以便除非主要更改布局更改,否则不会破坏我们的测试。

By byUserName = By.xpath("//*[@id='userTab']//*[text()='User Name']/..//input")
WebElement userNameField = webDriver.findElement(byUserName)
userNameField.sendKeys("my new user")// maybe a user click and then wait for the window to disappear
By submitLocator = By.xpath("//*[@id='userTab']//input[@type='submit']")
WebElement submit = webDriver.findElement(submitLocator)
submit.click()// use our helper method from Problem 1
waitForElementRemoval By.id("userTab")

问题3:法线元素交互方法不起作用!

就管理DOM的状态而言,GWT及其派生工具(Vaadin,GXT等)通常在幕后发挥作用。 对开发人员来说,这意味着您不必总是处理普通的<input>或<select>等元素。 仅通过常规方法简单地设置字段的值可能不起作用,并且使用WebDriver或Selenium的click方法可能不起作用。

WebDriver在这方面有所改进,但是问题仍然存在。

解决方案:不幸的是,只有一些解决方法

您可能会遇到的主要问题与在字段中键入和单击元素有关。

以下是一些我过去发现有必要的变体,可以避免点击无法正常运行。 如果遇到问题,请尝试一下。 这些示例在Selenium中,但是如果需要,可以将它们改编为适用于WebDriver中的相应调用。 如果您想直接使用示例,也可以将Selenium适配器用于WebDriver(WebDriverBackedSelenium)。

点击问题
有时,元素不会响应Selenium或WebDriver中的click()调用。 在这些情况下,通常必须在浏览器中模拟事件。 Selenium在2.0之前比WebDriver更是如此。

// Selenium's click sometimes has to be simulated with events.
def fullMouseClick(String locator) {selenium.mouseOver locatorselenium.mouseDown locatorselenium.mouseUp locator
}// In some cases you need only mouseDown, as mouseUp may be
// handled the same as mouseDown.
// For example, this could result in a table row being selected, then deselected.
def mouseOverAndDown(String locator) {selenium.mouseOver locatorselenium.mouseDown locator
}

打字问题
这些是过去在GWT无法识别键入的输入时能够成功使用的回旋输入法。

// fires only key events (works for most GWT inputs)
// Useful if WebDriver sendKeys() or Selenium type() aren't cooperating.
def typeWithEvents(String locator, String text) {def keyEvents = ["keydown", "keypress", "keyup"]typeWithEvents(locator, text, keyEvents)
}// fires key events, plus blur and focus for really picky cases
def typeWithFullEvents(String locator, String text) {def fullEvents = ["keydown", "keypress", "keyup", "blur", "focus"]typeWithEvents(locator, text, fullEvents)
}// use this directly to customize which events are fired
def typeWithEvents(String locator, String text, def events) {text.eachWithIndex { ch, i ->selenium.type locator, text.substring(0, i+1)events.each{ event ->selenium.fireEvent locator, event}}
}

请注意,必须通过反复试验找出有效的方法,在某些情况下,您在不同的浏览器中可能会得到不同的行为,因此,如果针对不同的环境运行功能测试,则必须确保您的方法适用于所有这些方法。

结论

希望你们中的一些人发现这些技巧有用。 那里也有类似的技巧,但我想汇编一套很好的示例和变通方法,以使处于类似情况的其他人不会陷入僵局,也不会在需要大量猜测和时间的问题上浪费时间。

参考: Carfey Software博客上的JCG合作伙伴提供的使用Selenium或WebDriver测试GWT应用程序 。

相关文章 :
  • 任何软件开发公司应存在的服务,实践和工具,第2部分
  • 为什么自动化测试可以提高您的开发速度
  • 不执行代码审查? 你的借口是什么
  • 软件可靠性的教训
  • 这是在您的业务逻辑之前!
  • 单元和集成测试的代码覆盖率

翻译自: https://www.javacodegeeks.com/2011/10/testing-gwt-apps-with-selenium-or.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL中有关TIMESTAMP和DATETIME的总结

一、MySQL中如何表示当前时间&#xff1f; 其实&#xff0c;表达方式还是蛮多的&#xff0c;汇总如下&#xff1a; CURRENT_TIMESTAMP CURRENT_TIMESTAMP() NOW() LOCALTIME LOCALTIME() LOCALTIMESTAMP LOCALTIMESTAMP() 二、关于TIMESTAMP和DATETIME的比较 一个完整的日期格式…

NYOJ 202 红黑树

红黑树 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;3描述 什么是红黑树呢&#xff1f;顾名思义&#xff0c;跟枣树类似&#xff0c;红黑树是一种叶子是黑色果子是红色的树。。。 当然&#xff0c;这个是我说的。。。 《算法导论》上可不是这么…

为对象添加方法mothod

Function.prototype.mothod function( name, fn ) { this.prototype[name] fn ; return this ; };转载于:https://www.cnblogs.com/40dadao/p/5816521.html

python爬虫cookie池 与ip绑定_Python爬虫:设置Cookie解决网站拦截并爬取蚂蚁短租

前言文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理。作者&#xff1a; EastmountPS&#xff1a;如有需要Python学习资料的小伙伴可以加点击下方链接自行获取我们在编写Python爬虫时&#xff0c;有时会遇到…

Java Secret:加载和卸载静态字段

总览 首先&#xff0c;很自然地假设静态字段具有特殊的生命周期&#xff0c;并且在应用程序的生命周期中一直存在。 您可以假设它们存在于内存中的特殊位置&#xff0c;例如C或类元信息的perm gen中的内存开始。 但是&#xff0c;得知静态字段驻留在堆上&#xff0c;可以具有任…

HTTP协议详解(真的很经典)

转自&#xff1a;http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx Author :Jeffrey 引言 HTTP是一个属于应用层的面向对象的协议&#xff0c;由于其简捷、快速的方式&#xff0c;适用于分布式超媒体信息系统。它于1990年…

NYOJ 63 小猴子下落

小猴子下落 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;3描述 有一颗二叉树&#xff0c;最大深度为D,且所有叶子的深度都相同。所有结点从左到右从上到下的编号为1,2,3&#xff0c;&#xff0c;2的D次方减1。在结点1处放一个小猴子&#xff0…

python科学计算与图形渲染_宁哥Python科学计算与图形渲染库课程

50dccd474759c0ffd343efcac14f8ab2.png (259.41 KB, 下载次数: 0)2019-4-9 12:23 上传课程目录章节1: NumPy基础知识课时1NumPy简介14:05课时2搭建NumPy开发环境&#xff0c;验证NumPy开发环境17:08课时3源代码和数据下载章节2: NumPy数组课时4创建多维数组09:20课时5获取单个数…

http协议说明

今天公司有同事让我给他讲一讲http..然后自己写了一个示例代码,这如果都看不懂.那我也没办法了.... 1 <?php2 3 //这里服务器以apache举例.nginx.iis.他们实际上处理方式的都是同理4 //申明http链接的数据包 注意最后面有两个换号.这是告诉apache.数据包的结束,如果后面没…

JBoss模块示例–模块化Web应用程序

最近&#xff0c;我读了为什么没有标准来开发真正的模块化Web应用程序&#xff1f; 由Patroklos Papapetrou撰写&#xff08; 在Java Code Geeks中也有介绍 &#xff09;。 受本文的启发&#xff0c;我决定检查实际使用的JBoss模块 。 这篇文章逐步描述了我的实验。 我首先想到…

由MySql漏洞导致电脑被入侵(特征为新增加名为piress的帐户)

今天开机&#xff0c;突然发现新增了一个名为piress的账户&#xff0c;突然间就意识到我的电脑可能被入侵了。后来发现网上很多人都遇到这样的问题。经过一步步的查证&#xff0c;原来最近MySQL爆出一个安全漏洞&#xff0c;远程登录mysql&#xff0c;尝试225次后就可以绕过身份…

multiprocessing.manager管理的对象需要加锁吗_Go: 内存管理和分配

本文基于Go1.13当不再使用内存时&#xff0c;标准库会自动执行Go的内存管理即从分配到回收。尽管开发者不需要处理它&#xff0c;但是Go的底层管理进行了很好的优化并且充满了有趣的概念。堆上的分配内存管理被设计可以在并发环境快速执行并且集成了gc。让我们从一个例子开始&a…

NYOJ 35表达式求值

表达式求值 时间限制&#xff1a;3000 ms | 内存限制&#xff1a;65535 KB难度&#xff1a;4描述 ACM队的mdd想做一个计算器&#xff0c;但是&#xff0c;他要做的不仅仅是一计算一个AB的计算器&#xff0c;他想实现随便输入一个表达式都能求出它的值的计算器&#xff0c;现在请…

Java EE6 CDI,命名组件和限定符

Java EE6的最大承诺之一就是简化了依赖注入的使用。 他们做到了&#xff0c;使用CDI 。 CDI代表Java EE的上下文和依赖注入&#xff0c;它提供了一个基础集&#xff0c;用于在企业应用程序中应用依赖注入。 在CDI之前&#xff0c;EJB 3还引入了依赖注入&#xff0c;但这有点基础…

c#获取当前目录的一些方法

【内容来源地址】&#xff1a;http://www.cnblogs.com/marcozh/archive/2008/10/19/1314667.html Assembly myAssembly Assembly.GetEntryAssembly(); string path myAssembly.Location; DirectoryInfo dr new DirectoryInfo(path); pathd…

linux里的进程简介

/sbin/init 内核启动的第一个用户级进程,引导用户空间服务 [kthreadd] 内核线程管理[migration/0] 用于进程在不同的CPU间迁移[ksoftirqd/0] 内核调度/管理第0个CPU软中断的守护进程[migration/1] 管理多核心[ksoftirqd/1] 内核调度/管…

python画画bup_Python中的高效Vector / Point类

实现高效的Vector / Point类的最佳方法是什么(甚至更好&#xff1a;是否有一个),可以在Python 2.7和3.x中使用&#xff1f;我找到了the blender-mathutils,但它们似乎只支持Python 3.x.然后是this Vector class,使用numpy,但它只是一个3D矢量.使用具有静态属性(x和y)的像kivy’…

CSDN 编程挑战——《coder的计算器》

coder的计算器 题目详情: coder现在已经上初中&#xff0c;也会用计算器实现 ,-,*,/和幂运算^了&#xff0c;但他觉得市场那些计算器太繁琐了&#xff0c;有很多他不认识的符号&#xff0c;所以他现在很想要能计算带括号的 ,-,*,/和幂运算^的混合表达式就可以了&#xff0c;你…

OpenShift Express:部署Java EE应用程序(支持AS7)

在过去的几年中&#xff0c;我越来越听到有关“云”服务的信息。 最初&#xff0c;我并不是很想尝试一下。 但是几个月后&#xff08;一年&#xff1f;&#xff09;&#xff0c;我决定看看这是怎么回事。 我从事Java EE开发已经超过7年了&#xff0c;所以我决定看看将Java EE应…

07 总结ProgressDialog 异步任务

1,ProgressDialog> //使用对象 设置标题 progressDialog.setTitle("标题"); //设置图标 progressDialog.setIcon(R.drawable.ic_launcher); //设置展示的内容 progressDialog.setMessage(&q…