Automated WebTesting with Selenium RC

Maria Marcano, Software Engineering at Nearsoft, http://mariangemarcano.blogspot.com/

Selenium RC (or Selenium 1) is a popular tool for writing automated tests of web applications. You can develop automated tests in the programming language of your choice such as c#, java, python, php, perl and ruby as well as running those tests on different combination of browsers such as Chrome, Firefox or IE.

Web Site: http://seleniumhq.org
Version
: Selenium RC 1.0.3
License & Pricing: All Selenium projects are licensed under the Apache 2.0 License.
Support: There are many places where you can find support, see http://seleniumhq.org/support/

Overview

Selenium project gathers a set of tools for writing automated tests of websites: Selenium RC (remote control), Selenium IDE, Selenium Grid and Selenium 2 (on beta) which is the next version of Selenium RC.

These tools emerged from a javascript library that was used to drive interactions on a webpage on multiple browsers called Selenium Core.

Selenium RC is a client/server based application that allows you to control web browsers using the following components

Running Selenium Server

Download Selenium RC from http://Seleniumhq.org/download/, the zip contains Selenium server, a Java jar file (Selenium-server.jar).

Selenium server must be running to be able to execute the tests. You can run it using the following command:

C:\>java -jar [SeleniumServerPath]\selenium-server.jar -interactive

Hello World Selenium RC

The following example uses c#, but a similar approach can be followed using others client driver libraries to develop tests in java, python, php, perl and ruby.

Using Selenium .Net client driver and Visual Studio 2010 (or 2008 Professional Edition)

  1. Create a test project.
  2. Add a reference to ThoughtWorks.Selenium.Core.dll on the project (this is found in the Selenium RC zip under Selenium-remote-control-1.0.3\Selenium-dotnet-client-driver-1.0.1 directory).
  3. Create a test class with the following structure:
using Selenium;
namespace TestProject1
{
	[TestClass]
	public class SeleniumPageTest
	{
		private ISelenium Selenium;
		[TestInitialize()]
		public void MyTestInitialize()
		{
			Selenium =
			new DefaultSelenium("localhost", 4444, "*firefox", "http://seleniumhq.org/");
			Selenium.Start();
		}
		[TestCleanup()]
		public void MyTestCleanup()
		{
			Selenium.Stop();
		}
		[TestMethod]
		public void CheckProjectsLink()
		{
			Selenium.Open("http://Seleniumhq.org/");
			Selenium.Click("link=Projects");
			Selenium.WaitForPageToLoad("3000");
			Assert.IsTrue(Selenium.IsTextPresent("Selenium IDE"));
		}
	}
}

Run this test in Visual Studio like you do with a regular unit test.

MyTestInitialize

This method initializes Selenium by creating an instance of DefaultSelenium (Default implementation of Selenium interface) specifying the following parameters:

The start method lunches the browser and begins a new Selenium testing session.

MyTestCleanup

The stop method ends the Selenium testing session and kills the browser.

CheckProjectsLink

This is a simple test that opens http://seleniumhq.org page, clicks on the "Projects" link, waits for the page to load (with a timeout of 3 seconds) and asserts that the text "Selenium IDE" is present on the page.

Benefits of having Selenium automated tests

Selenium automated tests have provided the following benefits on my projects:

When writing Selenium tests remember

Unstructured Tests

One common approach is to start developing automated tests having basic structure: test method, test initialize and cleanup, as shown in the SeleniumPageTest class.

This may work well at the beginning, but projects ends up with tests like the following:

[TestMethod]
public void RegisterUserTest()
{
// Starting Register User Test
Selenium.Open("www.mysite.com");
Selenium.Click("lnkRegister");
Selenium.WaitForPageToLoad("3000");
Selenium.Click("btnRegister");
Assert.IsTrue(Selenium.IsTextPresent("Please enter required fields"));
Selenium.Type("id_password", "123456");
Selenium.Type("id_password_2", "654123");
Selenium.Click("btnRegister");
Assert.IsTrue(Selenium.IsTextPresent("Passwords must match"));
Selenium.Type("id_email", "mytest@email.com");
Selenium.Type("id_first_name", "John");
Selenium.Type("id_last_name", "Doe");
Selenium.Type("id_password", "xxx#ZZ1");
Selenium.Type("id_password_2", "xxx#ZZ1");
Selenium.Click("id_acept_terms"); 
Selenium.Click("btnRegister");
Selenium.WaitForPageToLoad("3000");
Assert.IsTrue(Selenium.IsTextPresent("Welcome John Doe, logout"));
Selenium.Click("lnkLogout");
Selenium.WaitForPageToLoad("3000");
// RegisterUsTest Completed
}

The above test has the following issues:

Page Objects

Page Objects is a pattern that helps structure automated test code to overcome maintainability issues; this is how page objects helps:

Methods on a page object represent the "services" that a page offers (rather than exposing the details and mechanics of the page). For example the services offered by the Inbox page of any web-based email system:

How these are implemented shouldn't matter to the test.

The benefit is that there is only one place in your test suite with knowledge of the structure of the HTML of a particular (part of a) page.

Summary of Page Objects

  1. Represent the screens of your web app as a series of objects
  2. Do not need to represent an entire page
  3. Public methods represent the services that the page offers
  4. Try not to expose the internals of the page
  5. Generally don't make assertions
  6. Methods return other PageObjects
  7. Different results for the same action are modeled as different methods
  8. Check that the "Test Framework" is on the correct page when we instantiate the PageObject

Benefits achieved by applying page objects

Page Objects Tests

This is how unstructured tests will look after applying page object pattern:

[TestMethod]
public void TestRegisterUserEmptyFieldsValidation()
{
	var user = new User(); // empty user
	var registrationPage = RegisterUserExpectingErrors(user);
	Assert.IsTrue(registrationPage.IsRequiredFieldsMessagePresent());
}
[TestMethod]
public void TestRegisterUserPasswordMustMatch()
{
	var user = new User()
	{
		Password = "123456", Password2 = "654123"
	};
	var registrationPage = RegisterUserExpectingErrors(user);
	Assert.IsTrue(registrationPage.IsPasswordsMustMatchMessagePresent());
}
[TestMethod]
public void TestRegisterUserSucessfully()
{
	var user = new User()
	{
		Email = "mytest@email.com",
		FirstName = "John",
		LastName = "Doe",
		Password = "xxx#ZZ1",
		Password2 = "xxx#ZZ1"
	};
	var homePage = new HomePage(Selenium).SelectRegisterUser();
	var adminPage = registrationPage.FillUpRegistrationForm(user);
	.RegisterUserSucessfully();
	Assert.IsTrue(adminPage.IsWelcomeBackMessagePresent(user.FirstName));
	adminPage.Logout();
}
private RegistrationPage RegisterUserExpectingErrors(User user)
{
	var registrationPage = new HomePage(Selenium).SelectRegisterUser();
	return registrationPage.FillUpRegistrationForm(user)
	.RegisterUserExpectingErrors();
}

Writing maintainable automated tests

Below are key principles our team follows when writing automated tests:

  1. Readability: We want tests to be written in a way that even a final user can read them and understand them.
  2. Maintainability: Writing automated test with c# (or other programming language) and Selenium is equivalent as writing application code, so we should follow coding best practice and OO principles.
  3. Robustness & Flexibility: Robust tests that won’t break with small changes, being able to do changes with reduced impact. Tests should be repeatable: I can run it repeatedly and it will pass or fail the same way each time.
  4. Collaboration & Team Work: We want our tests structured in a way that allows easy collaboration and reuse between team members.

Summary of other Selenium projects

References

Selenium client libraries: http://seleniumhq.org/docs/05_Selenium_rc.html#programming-your-test

Xpather: https://addons.mozilla.org/en-US/firefox/addon/xpather/

Firebug: https://addons.mozilla.org/es-es/firefox/addon/firebug/

Page Objects: http://code.google.com/p/Selenium/wiki/PageObjects


More Software Testing Content


Click here to view the complete list of tools reviews

This article was originally published in the Summer 2011 issue of Methods & Tools