Load testing GWT applications with Selenium 2 and Gradle

This post shows how to do a load test on a GWT application that runs in production mode. Production mode means the application is deployed to a web server and only reachable through the HTTP protocol. It also means that GWT-RPC is enabled for the communication between the server and its clients.

JMeter is a very popular tool to do load tests on web applications. Unfortunately it is quite difficult to build a JMeter test plan when GWT-RPC is involved. The communication is very cryptic and building a test plan gets quite time consuming quickly.

An alternative to JMeter is to run many Selenium tests in parallel hitting on the application through the applications user interface. The following GWT load test is realized with Selenium 2.0 b2. The Gradle build automation tool is used to execute the Selenium tests in parallel, because as of this writing there is no release of Selenium 2 Grid. Selenium 1 Grid is not compatible with Selenium 2.

As Selenium is not really the best tool to do load testing it is quite difficult to put a heavy load on an application server. This problem can be solved by running the tests on many distinct computers. One could for example fire up a couple of toasters in a cloud service like EC2 to employ some test clients.

The following code shows a Gradle build file that executes a single JUnit test case several times in parallel.

import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.testing.Test;

apply plugin: 'groovy'

repositories {
	mavenCentral()
}

dependencies {
	groovy group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.10'
	testCompile fileTree(dir: 'lib', includes: ['*.jar'])
}

class LoadTest extends Test {

	FileTree getCandidateClassFiles() {
		FileTree candidateClassFiles = super.getCandidateClassFiles()

		11.times {
			candidateClassFiles += super.getCandidateClassFiles()
		}

		return candidateClassFiles
	}
}

task loadTest(type: LoadTest.class) {
	maxParallelForks = 4
}

To trigger a load test the Gradle task loadtest must be executed. This starts 4 test cases in parallel, because the parameter maxParallelForks is set to 4. The task loadtest is of type LoadTest as you can see in line 28. The given class for the type is also defined in this Gradle build file and extends the default Gradle test class. In there the getCandidateClassFiles method is overridden in a way that the method not only returns every single test case only once but several times. In this example 11 times more than usually. Every single test case would be executed 12 times in total now – four at the same time.

Writing a Selenium test case for a GWT applications is quite tricky. GWT can do a lot of fancy JavaScript in the frontend which has to be handled by the test implementation. The following code snippet is written in Groovy and shows a helpful method that can be used to get DOM elements from the GWT application under test.

RenderedWebElement findElement(By by) {
	RenderedWebElement element = null
	10.times {
		try {
			def temp = driver.findElement(by)
			if (temp instanceof RenderedWebElement) {
				if (temp.displayed) {
					element = temp
				}
			}
		} catch (org.openqa.selenium.NoSuchElementException e) {
			println "sleep 1500ms - waiting for $by"
			Thread.sleep(1500)
		} catch (org.openqa.selenium.StaleElementReferenceException e) {
			println "sleep 1500ms - Element '$by' is no longer attached to the DOM"
			Thread.sleep(1500)
		}
	}
	while (element != null && !element.enabled) {
		println "sleep 700ms - waiting for $element to become enabled"
		Thread.sleep(700)
	}
	return element
}

The findElement method repetitively tries (in this case 10 times) to find the desired element and also waits till the element is displayed and enabled. The element, for example a HTML checkbox, will be only returned when it is in the right state. Right means the test can make legal interactions with it.

Short URL for this post: http://blog.oio.de/AEy7i
This entry was posted in Build, config and deploy, Java and Quality and tagged , , , , . Bookmark the permalink.