Test web applications with Selenium RC

Introducing Selenium Remote Control

Selenium is a testing framework used for automated Web application testing. Get to know Selenium Remote Control (Selenium RC), which allows you to build tests for different browsers to ensure your Web applications are of the highest quality.

Nathan A. Good, Senior Consultant and Freelance Developer, Enterprise Frameworks

Nathan GoodNathan A. Good lives in the Twin Cities area of Minnesota. Professionally, he does software development, software architecture, and systems administration. When he's not writing software, he enjoys building PCs and servers, reading about and working with new technologies, and trying to get his friends to make the move to open source software. He's written and co-written many books and articles, including Professional Red Hat Enterprise Linux 3, Regular Expression Recipes: A Problem-Solution Approach, and Foundations of PEAR: Rapid PHP Development.



17 August 2010

Also available in Chinese Russian Japanese

Unit testing frameworks, such as JUnit, let you test the code that runs on your servers. However, in a typical web application, that service code is just a small part of the total code in the application. Such an application can also have a lot of code that is really only testable using a tool that works with a browser to test the application.

One of the more challenging aspects of testing web applications is testing the application's UI—the part of the application's code that is typically generated from HTML and JavaScript code. It runs in a browser, not in a server process, so it is only really testable from an Internet browser. Examples of this type of code include JavaServer Pages (JSP) pages, PHP code, and Ruby.

This article introduces one tool in the community—Selenium—that you can use to create and automate web tests. You will learn how to quickly create some sample tests, how to expand them, and how to use Selenium Remote Control to run them as automated tests.

Get to know Selenium RC

Selenium RC is part of a suite of tools from the Selenium project. It allows you to run tests that you've created in an automated fashion. Selenium RC runs on many different operating systems and can start an instance of different browsers, including Windows® Internet Explorer®, Mozilla Firefox, and Opera.

Using Selenium RC, you can run tests automatically as many times as you want. The tool also gives you the ability to create more complicated tests than you can create using Selenium IDE alone. You can add conditional statements and iteration to tests, which can help if you want to run tests with a set of data. You can also handle expected exceptions using the constructs available to you in unit testing frameworks such as JUnit.

Downloading and installing Selenium RC

To get started with Selenium RC, you must first download and install it. The Selenium server is simply a JAR file that you can run using the Java™ Runtime Environment (JRE). You can download the JAR file and other supporting files from the SeleniumHQ site (see Resources for a link).

When the download is complete, extract the archive file containing Selenium RC, and expand it to a location that you'll remember later. You can execute the Selenium server by running the following command:

java -jar selenium-server.jar

Sample application to test

This article uses a simple dynamic web application with JSP pages to demonstrate how Selenium RC works and can be used in automated testing. The simple web application has two pages: a login page and a page on which you can enter information such as your name and birth date, from which the application calculates your age and says "Hello."

This sample application provides an opportunity to show how you can execute tests to work with different conditions. The first page is shown in Listing 1. This is the simple login page that lets you log in to the web application. To keep things simple for this example, the login information is compared against some hard-coded strings.

Listing 1. The index.jsp page
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%

    if ("process".equals(request.getParameter("action")))
    {
        if ("user".equals(request.getParameter("username")) &&
                "secret".equals(request.getParameter("password")))
        {
            response.sendRedirect("enterInfo.jsp");
            return;
        }
    }

%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Login Page</title>
</head>
<body>
<form action="<%= request.getRequestURI() %>" method="POST">
<input type="hidden" value="process" name="action" />
<label for="username">Username:<br />
<input type="text" id="username" name="username" />
</label>
<br />
<label for="password">Password:<br />
<input type="password" id="password" name="password" />
</label>
<br />
<input type="submit" value="Login" />
</form>
</body>
</html>

The second page is shown in Listing 2. When you have entered your first name and birth date, the page simply says "Hello" and tells you your age as of today. This example is a bit contrived, because in most web applications, such information would require a login, and the data would be stored for your next login.

Listing 2. The enterInfo.jsp page
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
    "http://www.w3.org/TR/html4/loose.dtd">
<%@page import="java.util.Date"%>
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.text.ParseException"%>
<%!

private Date parseDate(String dateValue)
{
    Date returnDate = null;
    
    try
    {
        // this is not the most efficient of methods, and try...catch
        // statements ideally should not be used as business exception
        // processing...
        SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
        returnDate = dateFormat.parse(dateValue);
        
    } catch (ParseException pe)
    {
        // do nothing... 
    }
    
    return returnDate;
}

%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="<%= request.getRequestURI() %>" method="POST">
<input type="hidden" value="process" name="action" />
<label for="name">Your name:<br />
<input type="text" id="name" name="name" />
</label>
<br />
<label for="birthdate">Your birth date (in MM/DD/YYYY format):<br />
<input type="text" id="birthdate" name="birthdate" />
</label>
<br />
<%

    if ("process".equals(request.getParameter("action")))
    {
        // verify the date
        Date birthDate = parseDate(request.getParameter("birthdate"));
        
        if (birthDate == null)
        {
            // display the error messages...
            out.write("<p class=\"error\">Please enter a valid date.</p>");
        } else {
            // display the nice messages...
        }
        
    }

%>
<input type="submit" value="Submit" />
</form>
</body>
</html>

Writing the first test

To quickly write some tests that you can use as a foundation for your automated tests, you can use Selenium IDE to get started. Selenium IDE is a plug-in for Firefox that lets you record tests. You can then export the recorded tests so that you can add fanciness to them—conditions, iterations, and so on.

To get started with Selenium IDE, download it from the link in Resources. Install it as a Firefox plug-in by clicking the link. Firefox should prompt you to install the plug-in, and then you must restart the browser for the changes to take effect.

After you have the plug-in installed, start your server so you can begin using your web application. Open Selenium IDE by clicking Tools > Selenium IDE in Firefox. When Selenium IDE is open, click Record. After Selenium IDE is recording, it will remember all of the actions that you take in the browser. To log in to your sample application, perform the following steps:

  1. With Selenium IDE recording, navigate to the index.jsp web page.
  2. Type your user name.
  3. Type the valid password in the Password box.
  4. Click Login.

Upon successful login, your web application should go to the enterInfo.jsp page. At this point, your test has the actions in it, but so far, there is nothing to verify that your actions worked. Selenium needs to know what to look for in order to know that your enterInfo.jsp page is being rendered as expected.

You can add verify actions to make sure your application is displaying the correct content. While Selenium is still recording, perform the following steps:

  1. Right-click one of the HTML elements, such as the Your name label, and then click verifyTextPresent Your name:.
  2. Repeat step 1 with the Your birth date label.
  3. Click Record to stop recording.

If you want to see your test in action, click Run All (see Figure 1). The test will execute and pass.

Figure 1. Clicking Run All
Icon with a green play arrow and 3 green lines.

To see how Selenium IDE is really testing your application, go to your IDE and change the value of the valid user name. Re-deploy your application, and then click Run All again. This time, your tests will fail, because the web application will not display the enterInfo.jsp page with the correct labels.

Exporting the test to JUnit

Now that you have recorded your first test, you can export it for use in JUnit. With your test highlighted in Selenium IDE, click File > Export Test Case As > Java (JUnit) - Selenium RC. Type the name for your test (for example, IndexTests.java), and save it where you can remember it so that you can import it into Eclipse.

Perform the following steps:

  1. Create a new Java project that includes the Java unit tests built using JUnit.
  2. Download the Selenium RC binaries (see Resources for a link). Save the archive file to a location where you can import the files inside it into your new Java project in Eclipse.
  3. Create a new folder in your Java project called lib.
  4. Click File > Import, and then click File System from the list. Click Next.
  5. Browse to the location in which you extracted the Selenium RC files, and choose the selenium-java-client-driver-1.0.1 directory.
  6. Select the selenium-java-client-driver.jar from the list, and click OK to import the Selenium Java client driver JAR file into your project's lib directory.
  7. Import the Java file that you exported from Selenium IDE into the src directory of your new Java project.

The first thing you'll notice is that you will get many compile errors. First, your new Java file is probably not in the correct package, because it's directly in the src folder. Second, the JUnit or Selenium classes cannot be found. Fortunately, these errors are easy to resolve using Eclipse.

Resolving errors in Eclipse

Resolve the package errors by clicking the error, and then pressing Ctrl-1 to open the hints. Select Move MyTest.java to package 'com.example.mywebapp.tests'. Eclipse creates the package structure for you and moves the file.

Adding the JUnit test

Now, add the Selenium and JUnit test by clicking the Java project in Package Explorer and clicking Build Path > Configure Build Path. On the Libraries tab, click Add JARs, and select the selenium-java-client-driver.jar file. Click OK.

When the Java source file is compiling, it should look similar to Listing 3.

Listing 3. The JUnit test based on the exported code from Selenium IDE
package com.example.mywebapp.tests;

import org.junit.Before;
import org.junit.Test;

import com.thoughtworks.selenium.SeleneseTestCase;

public class EnterInfoTests extends SeleneseTestCase {
    
    @Before
    public void setUp() throws Exception {
        setUp("http://localhost:8080/tested-webapp/index.jsp", "*firefox");
    }
    
    @Test
    public void testBadDate() {
        doLogin();
        selenium.type("name", "User");
        selenium.type("birthdate", "@#$#@");
        selenium.click("//input[@value='Submit']");
        selenium.waitForPageToLoad("30000");
        verifyTrue(selenium.isTextPresent("Please enter a valid date"));
    }
    
    @Test
    public void testValidDate() {
        doLogin();
        selenium.type("birthdate", "12/2/1999");
        selenium.click("//input[@value='Submit']");
        selenium.waitForPageToLoad("30000");
        verifyFalse(selenium.isTextPresent("Please enter a valid date"));
    }
    
    private void doLogin()
    {
        selenium.open("/tested-webapp/index.jsp");
        selenium.type("username", "user");
        selenium.type("password", "secret");
        selenium.click("//input[@value='Login']");
        selenium.waitForPageToLoad("30000");
    }
}

If you are unable to download and install Selenium IDE because you have restrictions that prevent you from using Firefox, you can still write tests that you can run using Selenium RC. Just use the examples shown here as a start and the documentation for Selenium provided in Resources.


Viewing the test results

Now that you have the first example test written, you can see it in action by starting the Selenium server and running the test as a standard JUnit unit test. Start the Selenium server by typing the following command:

java -jar selenium-server.jar

Running the server from the IDE

For a fully integrated experience, you can set up an external tool configuration in Eclipse to start the Selenium server directly from Eclipse. Click Run > External Tools > External Tool Configurations to set up the configuration. Simply enter the command for starting the server into a new tool configuration.

After you have the Selenium server started, you can run the unit test by right-clicking the IndexTest.java file, and then clicking Run As > JUnit Test. It may take a while as the Selenium server starts up an instance of your browser and runs the tests. When the test is finished, you will see the same output in Eclipse as with normal unit tests.


Digging deeper

Now that you've used Selenium IDE to create a simple test and exported it as a Java file, create a more complicated test to verify the functions of the enterInfo.jsp page. The example test is shown in Listing 4.

Listing 4. The JUnit test for testing enterInfo.jsp
package com.example.mywebapp.tests;

import org.junit.Before;
import org.junit.Test;

import com.thoughtworks.selenium.SeleneseTestCase;

public class EnterInfoTests extends SeleneseTestCase {
    
    @Before
    public void setUp() throws Exception {
        setUp("http://localhost:8080/tested-webapp/index.jsp", "*firefox");
    }
    
    @Test
    public void testBadDate() {
        doLogin();
        selenium.type("name", "User");
        selenium.type("birthdate", "@#$#@");
        selenium.click("//input[@value='Submit']");
        selenium.waitForPageToLoad("30000");
        verifyTrue(selenium.isTextPresent("Please enter a valid date"));
    }
    
    @Test
    public void testValidDate() {
        doLogin();
        selenium.type("birthdate", "12/2/1999");
        selenium.click("//input[@value='Submit']");
        selenium.waitForPageToLoad("30000");
        verifyFalse(selenium.isTextPresent("Please enter a valid date"));
    }
    
    private void doLogin()
    {
        selenium.open("/tested-webapp/index.jsp");
        selenium.type("username", "user");
        selenium.type("password", "secret");
        selenium.click("//input[@value='Login']");
        selenium.waitForPageToLoad("30000");
    }
}

The example test used the LoginTest class shown in Listing 3 as a starting point. The doLogin() function has the code to log you in to the application, which is used at the start of the tests to get you to the proper point.

The testBadDate() method is used to enter bad values into the birthdate field on the form, and then submit it. It verifies that the appropriate error message is displayed if the date is incorrect. The testValidDate() method tests the valid date on the form and makes sure the message that provides the user's age is correct.

Using the power of Java technology available to you in JUnit, you can loop through examples, add conditions to your tests, and expect exceptions. See the links in Resources to learn more about JUnit and unit testing.


Automating the tests

Now that you have the tests running in the Eclipse IDE, with the help of an Apache Ant script and a few targets, you can automate the tests completely. After you have this Ant script, you can use tools such as Hudson or CruiseControl (see Resources) to run these tests continuously.

To automate the test, you can use an Ant script that employs the JUnit target to execute the Selenium RC tests. The script is shown in Listing 5.

Listing 5. An Ant script for running the Selenium tests
<project name="tested-webapp-tests" default="run-tests" basedir=".">

    <property name="selenium.server.jar" 
        value="/path/to/selenium-server.jar" />
    <property name="src" value="${basedir}/src" />
    <property name="build" value="${basedir}/bin" />
    <property name="lib" value="${basedir}/lib" />
    <!-- Could be defined in Ant runtime classpath, but here is better -->
    <property name="hamcrest.home" 
        value="/path/to/eclipse/plugins" />
    <property name="junit4.home" 
        value="/path/to/junit4/" />

    <path id="classpath">
        <fileset dir="${lib}" includes="**/*.jar" />
        <fileset dir="${hamcrest.home}" includes="org.hamcrest.core*.jar" />
        <fileset dir="${junit4.home}" includes="junit.jar" />
    </path>

    <target name="start-selenium-server">
        <java jar="${selenium.server.jar}" fork="true" spawn="true">
            <arg line="-timeout 30" />
        </java>
    </target>

    <target name="compile-tests">
        <javac srcdir="${src}" destdir="${build}" />
    </target>

    <target name="run-tests" depends="compile-tests">
        <junit printsummary="false" 
            showoutput="true" 
            outputtoformatters="true">
            <formatter type="brief" usefile="false" />
            <classpath>
                <path refid="classpath" />
                <pathelement path="${build}" />
            </classpath>

            <batchtest fork="yes">
                <fileset dir="${src}">
                    <include name="**/*Tests.java" />
                </fileset>
            </batchtest>
        </junit>
        <echo message="Finished running tests." />
    </target>

    <target name="stop-selenium-server">
        <get taskname="selenium-shutdown" 
src="http://localhost:4444/selenium-server/driver/?cmd=shutDownSeleniumServer" 
            dest="result.txt" 
            ignoreerrors="true" />
    </target>

    <target name="run-all">
        <parallel>
            <antcall target="start-selenium-server">
            </antcall>
            <sequential>
                <echo taskname="waitfor" message="Wait for proxy server launch" />
                <waitfor maxwait="1" maxwaitunit="minute" checkevery="100">
                    <http 
url="http://localhost:4444/selenium-server/driver/?cmd=testComplete" />
                </waitfor>
                <antcall target="run-tests">
                </antcall>
                <antcall target="stop-selenium-server">
                </antcall>
            </sequential>
        </parallel>
    </target>

</project>

The Ant script has three targets. The first target, start-selenium-server, starts the Selenium server in forked and spawned mode so that it runs in the background. The run-tests target actually executes the JUnit tests, and the stop-selenium-server target stops the server by calling a URL that sends the server a shutdown command.

Using an Ant script like this one, you can run the Selenium tests in an automated fashion by scheduling them or using the Ant script in a continuous integration tool. See Resources for links to more information about continuous integration builds.


Running the tests in other browsers

As written so far in this example, the tests are executed in Firefox. However, there may be times when it is necessary to test the web application in other browsers to make sure functions work across browsers.

You may have noticed that when the Selenium tests where set up in the setUp() method of the JUnit test, *chrome was passed as the second parameter to the parent's setUp() method. This parameter starts an instance of the Firefox browser.

To run the test for a different browser, simply supply the name of the browser as the second argument. For example, *iexplore uses Internet Explorer as the browser instead of Firefox. Use *opera for the Opera browser or *safari for Apple Safari.

Note that the browser must be supported on the operating system on which you are running the tests. You will get exceptions and, therefore, failed tests if you attempt to execute tests for a browser that doesn't exist on your operating system, such as *safari or *iexplore on a system running Linux®.


Conclusion

This article introduced Selenium and two of its components: Selenium IDE and Selenium RC. Selenium IDE is an easy way to start writing tests for your web applications. Selenium RC is a component that you can use to add features to and automate your tests.

Automated web application testing from the browser perspective can be a great way to augment existing unit tests that cover other parts of your application. With automated testing, developers can get faster feedback on problems, and testing regressions becomes faster.

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=508345
ArticleTitle=Test web applications with Selenium RC
publish-date=08172010