使用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 = 20
    WebDriverWait 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 resubmit

submitButton.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 locator
    selenium.mouseDown locator
    selenium.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 locator
    selenium.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应用程序

相关文章 :

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值