Over a million developers have joined DZone.

Web Application Testing Using Selenium

In this article, Bipin Patwardhan provides a little background info about using Selenium for web app testing and covers how to create a simple, CSV-based command framework for web application testing, using Selenium 2.

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

Introduction

While mobile applications seem to be the rage these days, enterprises still have to focus on the development of web applications for many of their activities. As with any software, web applications need to be tested thoroughly before deployment. While test suites have been developed for the unit testing of (back-end/business logic) code developed in say Java or C#, testing the front-end of a web application is still a manual activity (across many projects).

Many tools, like HP QuickTestPro (QTP) and Selenium IDE are popular amongst development teams for automated testing of web applications. But, automated tests developed using such tools are quite brittle in nature. This is because many tools follow a ‘record and playback’ approach that captures user interaction with the web application that is simply played back at a later point in time. In other words, such tools record the user’s actions while she navigates a web application and then simply plays those actions each time the web application has to be navigated. While ‘record and play’ is the most basic feature provided by such tools, many of them also provide a scripting language/environment that can be used to perform additional validations on the web application to be tested. But, this kind of scripting introduces an additional level of complexity in the project, where testers need to be taught a new scripting language. In many cases, this additional complexity is also a deciding reason why automation is not popular.

The Selenium and WebDriver Projects

The Selenium project was started in 2004 as a JavaScript library that allowed interactions with a web page. As it was based on Javascript, it was possible to run the library across multiple browsers. The JavaScript library eventually became Selenium Core as well as the base for Selenium RC (Remote Control) and Selenium IDE. Due to limitations that browsers placed on JavaScript, the library was not able to provide a comprehensive toolkit for testing.

In mid of 2006, Google started working a project named WebDriver, with the intention of communicating with the browsers directly, thus overcoming some of the limitations of Selenium. Over a period of time, it was felt that the two projects complement each other and it was decided to merge the two, while retaining the name Selenium.The merged effort is known as Selenium 2.

It is important to note that Selenium IDE (Integrated Development Environment)—a part of Selenium 1 and supported by Selenium 2—is a prototyping tool for building test scripts. It is a Firefox plugin that provides an easy-to-use interface for developing automated tests. The Selenium IDE has a recording feature which records user actions as they are performed. The recorded actions can be exported for later execution. Given that Selenium IDE is a Firefox plugin, it is not possible to use it with other browsers for recording. Additionally, though user actions can be stored for later execution, it does not qualify as an automated test execution framework. The Selenium project recommends that enterprises develop their own web automation test suites by combining the Selenium API with any of the supported programming languages. Using the Selenium API, it is possible to control the actions of the browser. By defining suitable testing constructs, an enterprise can easily develop a test suite that can be used to test web applications in an automated manner.

One of the most interesting features of Selenium is that it supports multiple browsers. Thus, if we define a web application testing framework that makes use of HTML standards, it is possible to have the application tested across multiple browsers. Selenium supports Google Chrome, Mozilla Firefox, Microsoft Internet Explorer, Safari, and Opera. If you do not wish to launch a browser window while testing the application, it is also possible to use the HtmlUnit browser, which works completely in memory.

Custom Web Application Testing Using Selenium

In this section, I will cover how I created a simple, CSV-based command framework for web application testing, using Selenium 2. As the Selenium project is available for Java projects, and the application I developed is also in Java, this should be a good example.

In terms of functionality, the application is very simple. The application provides a few commands that can be used to fetch web content using a URL. After fetching the page, its content can be verified using provided commands. If any of the commands fail the validation test, the web page is considered to not match the required specification and the test is considered to be a failure. All the interactions that the application has with the web application, as well as the validations it performs, are recorded in a log file using Log4J. Thus, each time a test run is performed, a log is generated, which serves as documentation evidence that can be shared with the customer.

The application accepts an input file (a CSV file) that contains commands. Each command accepts parameters and is represented by a corresponding Java class. The application, on encountering the command, loads the appropriate Java class and executes it, passing it all the parameters specified in the command file. Each command returns a Boolean value, with ‘True’ indicating that the command executed successfully and a ‘False’ indicating failure. The user can configure the application such that it continues execution even in the case of command failures. By default, the application will stop further execution if a command returns ‘False’. Each command updates the log with suitable messages. The verbosity of the message can be controlled by setting appropriate parameters of Log4J. The log file, as mentioned earlier, serves as documentary evidence of the validations performed.

Dynamic Loading of Commands

For flexibility and to support expandability, the implementation classes corresponding to the commands, are loaded dynamically using the reflection principles of Java. Due to dynamic loading, new functionality can be added to the application, without the application needing to undergo drastic updates for each change. To add a new command, we need to create a Jar file containing the new command and include it in the CLASSPATH of the application. Additionally, in the command file, we need to register the new command with the command register (the command register is used to match the name of the command, as specified in the input file, with an implementation that can be executed).

A Few Commands

Some of the commands that are supported by the application are:

browser

This command allows the user to define the browser that is launched for testing the web application. The application supports Mozilla Firefox, Microsoft Internet Explorer, Google Chrome, and HtmlUnit. The most interesting feature of HtmlUnit is that it does not launch a window and thus is very useful if web application testing has to be carried out from a server or from a cloud-based environment. The syntax of the command is:

browser, [chrome/firefox/ie/htmlunit] [, path to browser]

A sample of the command is:              

browser, chrome, C:\\Selenium\\chromedriver.exe

page

This command is used to provide the URL of the page that is to be fetched and validated. The syntax of the command is:

page, url

A sample of the command is:

page, http://localhost:8080/WebDriver/sourceLogin.jsp

wait

Given that the application has to connect to the Internet and download web pages, it may take some time for the requested page to be downloaded and become available for validation. This command has been provided to account for this delay. If the application does not allow for some delay in fetching the requested page, it will proceed to the next command and will try to perform validations on web elements that have not yet been fetched, causing the test to fail. The syntax of the command is:

wait, milliseconds

A sample of the command is

wait, 10000

Instead of this hard-wired wait duration, it is also possible to design a command that waits for shorter time duration till such time that the specified web element become available on the web page. Such a command will have to keep checking for—in a loop and a small delay—the presence of the required web element. By allowing for a timeout within which the web element has to be located, the application can fail the test if the web page or the web element does not become available and continue execution.

verifyTitle

This command is used to verify the title of the web page that has been fetched. Typically, web pages have a title and verification of the same helps ensure that we have indeed received the correct page. The syntax of the command is:

verifyTitle, valueToCheck

A sample of the command is:

verifyTitle, Hello World

verify

This command is used to verify specific elements on the web page that has been fetched using the ‘page’ command. This command is a bit complex as compared to other commands supported by the application. This is because the command allows us to verify different aspects of the web page. For example, we can use this command to verify that a link (specified by an ‘id’) is present on the web page. We can also verify the value of an attribute of a web element. For example, we can verify that the color of an element is ‘Red’. This command is the backbone of the application, allowing us to validate different parts of the web application to ensure compliance. The syntax of the command is:

verify [, field/attribute/value] [,id/name/xpath][, fieldname] [,attributeName] ,valueToCheck

The various flavours of the command are:

verify, field, id, fieldname, valueToCheck

verify, field, name, fieldname, valueToCheck

verify, field, xpath, fieldname, valueToCheck

verify, value, id, fieldname, valueToCheck

verify, attribute, xpath, fieldname, attributeName, valueToCheck

A few samples of the command are:

verify, value, id, one, Happy

verify, value, //input[@id = 'one'], Harry

close

This command is used to close the browser instance launched by the application, effectively ending the testing session. The syntax of the command is

close

Command Implementation

After describing some of the commands supported by the application, I will provide implementations of some of the commands in this section.

Browser.java

The browser command is used to specify the browser to be used for the test session. Presently, the application supports Google Chrome, Mozilla Firefox, Microsoft Internet Explorer, and HtmlUnit. Though a single ‘browser’ command is used, the name of the specific browser that is to be used for testing needs to be specified.

package sts.commands;

import org.openqa.selenium.WebDriver;

import sts.Environment;

public class Browser extends GenericCommand
{
  public Browser()
  {
    super();
  }
  @Override
  public Object execute(Environment env, String[] params)
  {
    WebDriver driver = null;
    System.out.println("Initializing browser.");
    if ( "chrome".equalsIgnoreCase(params[1]) ) {
      driver = new BrowserChrome().execute(env, params);
    } else if ( "htmlunit".equalsIgnoreCase(params[1]) ) {
      driver = new BrowserHtmlUnit().execute(env, params);
    } else if ( "firefox".equalsIgnoreCase(params[1]) ) {
      driver = new BrowserFirefox().execute(env, params);
    } else if ( "ie".equalsIgnoreCase(params[1]) ) {
      driver = new BrowserIE().execute(env, params);
    }
    env.setWebDriver(driver);
    return driver;
  }
}


BrowserChrome.java

BrowserChrome is not a command that can be specified in the input file. It, along with other browser classes, is a helper class that allows the Browser command to launch the appropriate browser instance. The reason for a dedicated helper class for each browser is due to the way various parameters need to be configured for each browser during startup. While it is possible to implement everything in the Browser class, it would make the class difficult to maintain. This class is used to launch an instance of the Google Chrome browser.

package sts.commands;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.chrome.ChromeDriver;

import sts.Environment;

public class BrowserChrome extends GenericCommand
{
  publicBrowserChrome()
  {
    super();
  }
  @Override
  public WebDriver execute(Environment env, String[] params)
  {
System.setProperty("download.prompt_for_download", "false");
System.setProperty("webdriver.chrome.driver", params[2]);
return new ChromeDriver();
  }
}


BrowserHtmlUnit.java

BrowserHtmlUnit is similar to the BrowserChrome class. It is a helper class used to launch an instance of the HtmlUnit browser.

package sts.commands;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.htmlunit.HtmlUnitDriver;

import sts.Environment;

public class BrowserHtmlUnit extends GenericCommand
{
  publicBrowserHtmlUnit()
  {
    super();
  }

  @Override
  public WebDriver execute(Environment env, String[] params)
  {
    HtmlUnitDriver driver = new HtmlUnitDriver();
driver.setJavascriptEnabled(true);
    return driver;
  }
}


VerifyTitle.java

The VerifyTitle class is used to verify the title set for the page loaded in the browser.

package sts.commands;

import org.openqa.selenium.WebDriver;
import sts.Environment;

public class VerifyTitle extends GenericCommand
{
  publicVerifyTitle()
  {
    super();
  }
  @Override
  public Object execute(Environment env, String[] params)
  {
    WebDriver driver = env.getWebDriver();
    String value = driver.getTitle();
    if ( value == params[1] ) {
      System.out.println("Title matches");
    } else {
      System.out.println("Title does not match");
    }
    return null;
  }
}


Verify.java

The Verify class is a multi-functional class that can be used to verify the presence of a web element on the loaded web page, as well to verify various characteristics of the elements on the web page.

package sts.commands;

import org.openqa.selenium.By;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.WebElement;

import sts.Environment;

public class Verify extends GenericCommand
{
  public Verify()
  {
    super();
  }
  protected Object verifyField(WebDriver driver, String[] params)
  {
    By fieldBy = null;
    WebElement field = null;
    if ( "id".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.id(params[3]);
    } else if ( "name".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.name(params[3]);
    } else if ( "xpath".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.xpath(params[3]);
    }

    if ( fieldBy != null ) {
      field = driver.findElement(fieldBy);
      if ( field != null ) {
        return new Boolean(true);
      }
    }
    return new Boolean(false);
  }
  protected Object verifyFieldAttribute(WebDriver driver, String[] params)
  {
    By fieldBy = null;
    WebElement field = null;
    if ( "id".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.id(params[3]);
    } else if ( "name".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.name(params[3]);
    } else if ( "xpath".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.xpath(params[3]);
    }

    if ( fieldBy != null ) {
      field = driver.findElement(fieldBy);
      if ( field != null ) {
        String value = field.getAttribute(params[4]);
        if ( value.equals(params[5]) ) {
          return new Boolean(true);
        }
      }
    }
    return new Boolean(false);
  }

  protected Object verifyFieldValue(WebDriver driver, String[] params)
  {
    By fieldBy = null;
    WebElement field = null;
    if ( "id".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.id(params[3]);
    } else if ( "name".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.name(params[3]);
    } else if ( "xpath".equalsIgnoreCase(params[2]) ) {
      fieldBy = By.xpath(params[3]);
    }

    if ( fieldBy != null ) {
      field = driver.findElement(fieldBy);
      if ( field != null ) {
        String value = field.getText();
        if ( value.equals(params[4]) ) {
          return new Boolean(true);
        }
      }
    }
    return new Boolean(false);
  }

  @Override
  public Object execute(Environment env, String[] params)
  {
    WebDriver driver = env.getWebDriver();
    By fieldBy = null;
    WebElement field = null;
    if ( "field".equalsIgnoreCase(params[1]) ) {
      verifyField(env.getWebDriver(), params);
    } else if ( "attribute".equalsIgnoreCase(params[1]) ) {
      verifyFieldAttribute(env.getWebDriver(), params);
    } else if ( "value".equalsIgnoreCase(params[1]) ) {
      verifyFieldValue(env.getWebDriver(), params);
    }
    return null;
  }
}


Sample Input File

Here is a sample input file that can be used for testing.

browser, chrome, C:\\chromedriver.exe
wait, 1000
page, http://localhost:8080/WebDriver/sourceLogin.jsp
wait, 1000
verifyTitle, Source Login
verify, field, id, username
set, id, username, user1
set, id, password, pass123
srcSubmit, id, submit
wait, 1000
close


Sample Page

Here is the sample page that can be used for testing.

<html>
<head>
<title>Source Login</title>
</head>
<body>
  <h1>Source Login</h1>
  Hello World!!!
  <p/>
  <form action="sourcePageOne.jsp" method="GET">
    <table align="center">
      <tr><td>Source User name:</td><td><input id="username" name="username"/></td></tr>
      <tr><td>Source Password:</td><td><input id="password" name="password"/></td></tr>
      <tr><td colspan="2"><input type="submit" id="submit" value="Submit"/></td></tr>
    </table>
  </form>
</body>
</html>


Conclusion

With enterprises focusing improving efficiency using various automation techniques, I believe that automated web application testing will once again be a key focus area. While there are many commercial tools available for this purpose, the Selenium open source project provides a mature, viable alternative.

Selenium provides a powerful and feature-rich library that can be used to develop an automated web application testing framework suitable for the needs of the enterprise.As provided, the library may not seem powerful. But, the power of the library can really be unlocked by developing an application as per the need of the enterprise. Using Selenium and a custom application, an enterprise can develop and deploy a command-based, automated web application testing suite. By using an automated testing application, we can make the testing process a part of the continuous integration cycle. The command-based approach allows for easy verification of the test cases and as well as providing a consistent testing approach.

Links

Choosing Your Selenium Tool: http://www.seleniumhq.org/docs/01_introducing_selenium.jsp#choosing-your-selenium-tool

Automated web application testing with Selenium IDE: http://stackoverflow.com/questions/7239430/automated-web-application-testing-with-selenium-ide

Automating Functional Tests Using Selenium: https://www.computer.org/csdl/proceedings/agile/2006/2562/00/25620270.pdf

Automated Testing of Web Pages Using Selenium-Web Driver: http://www.codeproject.com/Articles/843207/Automated-Testing-Of-Web-Pages-Using-Selenium-Web

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
java ,selenium ,selenium 2 ,testing ,automation ,web application

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}