Load Testing web application with Selenium and TestNG

I’ve used Selenium for while to do verification tests of web applications, recently I discovered a very simple way to use it with TestNG and Maven to do some performance testing. TestNG allows for the use of annotations to allow multi-threading and iterations.

pom.xml:

<dependencies>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.8.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.44.0</version>
<scope>test</scope>
</dependency>
<dependencies>

And as for a simple test to get started with… scripting of steps is available online or could be in a future blog post.

/*
* COPYRIGHT. none
*/
package com.example.selenium;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Simple test example for Selenium
*/
public class SeleniumTest {

private static final Logger LOGGER = LoggerFactory.getLogger(SeleniumTest.class);
/**
* TODO Un-comment or change if needed to set your local path!
*/
@BeforeClass
public void oneTimeSetUp() {
System.out.println("-------------------------------------- init ----------------------------------------");
//System.setProperty("webdriver.firefox.bin","C:\\path\\to\\firefox.exe");
}
/**
* NOTE: uses TestNG - behaves differently than JUnit
*/
@Test(invocationCount = 1, threadPoolSize = 5)
public void testLoadApp() {

final String fn = "testLoadApp";
final String baseUrl = "http://www.giantgeek.com/index.php";
LOGGER.debug("[START] Thread Id: {} is started!", Thread.currentThread().getId());

WebDriver driver = null;
final long start = System.currentTimeMillis();
try{
driver = (WebDriver)new FirefoxDriver();
driver.get(baseUrl);

final String actual = driver.getTitle();
LOGGER.debug("Page Title is {}", actual);
final String expected = "GIANTGEEK.COM";
Assert.assertEquals(actual,expected);
//perform whatever actions, like login, submit form or navigation

}catch(final WebDriverException ex){
LOGGER.warn(fn+":WebDriverException:{}",ex);
}catch(final Exception ex){
LOGGER.warn(fn+":Exception:{}",ex);
}
finally {
final long elapsed = System.currentTimeMillis() - start;
LOGGER.debug("[END] Thread Id: {}, elapsed={}", Thread.currentThread().getId(),elapsed);
if(driver != null){
driver.quit();
}
}
}
}

WARNING: Selenium Tests MAY fail if the browser used for testing is updated in the Operating System. Updating the pom.xml to a newer release usually helps!

REFERENCES:

HTA/.hta files

HTA/.hta files are a technology that Microsoft implemented in it’s browsers MSIE 5-9 to support rich web applications, MSIE 10 and newer do not implement it and must be forced into MSIE 9 compatibility mode.

Most often HTA was/is used to hide the browser controls (chrome) from the user to provide dialog windows.

EXAMPLE:

<html>
<head>
<meta http-equiv="x-ua-compatible" content="ie=9" />
<!-- does not work in 10 or above, so force it back down -->
<hta:application id="example"
applicationname="example"
border="1"
caption="no"
icon="icon.ico"
navigable="no"
scroll="no"
showintaskbar="no"
singleinstance="yes"
sysmenu="no"
windowstate="normal">
</hta:application>
</head>
</html>

Apache MIME Type:

AddType application/hta .hta

REFERENCES:

Cloudflare CDN (Content Delivery Network)

Best practices for web applications often call for the use of a CDN. Those of you that have worked with YSlow! are likely very accustomed to seeing warnings for this reason. I’ve found that CloudFlare is very easy to setup, and for basic services costs absolutely nothing. In addition to the obvious performance advantages of using a CDN to offload much of your network traffic, it also has the advantage of improved security.

CDN’s work by caching a copy of your static content at several locations around the world, making it closer and faster for your users.

Implementation takes only minutes as it requires that you:

  1. create a (free) account,
  2. retrieve your existing DNS values from your current provider,
  3. determine direct vs. CDN “cloud” routing for each subdomain,
  4. change your DNS records to point to the CloudFlare DNS servers

Some additional advantages I’ve seen since implementing:

  • Site remains available in limited capability to users during server outages or upgrades.
  • Simplified network configuration as all requests can be sent outside of the LAN for users local to the servers
  • IPv6 dual-stack support

REFERENCES:

HTML5 offline appcache manifest

In my testing, you don’t need to fully embrace HTML5 markup to take advantage of the “offline” functionality, you simply need to add the attribute and related files to your existing website/page. Any modern browser that supports HTML5 should automatically recognize the offline content and use it when appropriate, unfortunately no version of MSIE yet supports this.

<html manifest="/offline.appcache">

In that file, you must then specify the offline behavior, something like this is a good start:

CACHE MANIFEST
#This is to provide minimal HTML5 offline capabilities
#MIME mapping must be 'appcache=text/cache-manifest'
#Reference to this file is per page, you can have different ones in an app.
#Common image files and css may be 'cached'
CACHE:
/index.html
/css/offline.css
NETWORK:
*
FALLBACK:
/ /offline.html

On the server side, you’ll have to serve up that file with the appropriate MIME type (text/cache-manifest, for ApacheHTTPD you simply need to add one line to httpd.conf:

AddType text/cache-manifest .appcache

REFERENCES: