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

Selenium Server : Uses Selenium core and browser�s built-in JavaScript interpreter to process selenese commands (such as click, type) and report back results.

: Uses Selenium core and browser�s built-in JavaScript interpreter to process selenese commands (such as click, type) and report back results. Selenium Client Libraries: Are the API�s for the programming languages to communicate with Selenium server.

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)

Create a test project. 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). 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:

Host name on which the Selenium server is running (localhost).

The port on which Selenium server is listening (when we started Selenium server by default it listens on port 4444).

The command string used to launch the browser, e.g. "*firefox", "*iexplore" or "c:\\program files\\internet explorer\\iexplore.exe",

The starting URL, Selenium starts the browser pointing at the Selenium resources on this URL (http://seleniumhq.org/).

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:

Execute regression tests easily and have quick feedback about the application�s status.

Run the same set of tests with different browsers, we�ve caught functional errors present in one browser and not in the others.

Run the same set of tests on different code branches (and browsers) on daily basis in a continuous integration environment.

When writing Selenium tests remember

Tests that access elements by id run faster than accessing elements using xpath expressions.

Use tools like xpather and firebug to quickly locate elements.

Selenium IDE is handy to record Selenium commands while executing interactions on the UI.

Run your Selenium tests automatically in a controlled environment using continuous integration tools which involves automated build, deploy and testing process.

You can run multiple tests at the same time running Selenium server on different ports.

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:

Code duplication and tests have high dependency with the page�s HTML structure. This means that changes in a single page will affect different tests. When the application changes, tests will start breaking and this will be hard to maintain over the time.

Readability issues: Tests are not easy to read. Is difficult to know what the test is doing.

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:

Compose a new email

Read a single email

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

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

Benefits achieved by applying page objects

There is one place having the knowledge of the structure of the pages (the page object)

Navigation between the pages.

Changes in a page are in one place (reducing duplication).

Easy to locate code.

Less dependency between the test cases and Selenium, since most Selenium code will be located on the page object.

As the amount of tests increases, the page objects represent a smaller percentage of the overall test code.

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:

Readability: We want tests to be written in a way that even a final user can read them and understand them. 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. 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. 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

Selenium IDE is a Firefox add-on that allows you to record and playback actions performed on a webpage. Also you can format recorded tests to port them to Selenium RC (C#, java, perl, php, python, ruby), when doing so modify them with maintainability considerations mentioned on the article. Using this is fine to start, but it quickly becomes faster coding the tests directly.

Selenium Grid is a solution to scale Selenium RC tests, allowing running tests on parallel, different machines and environments.

is a solution to scale Selenium RC tests, allowing running tests on parallel, different machines and environments. Selenium 2 is the next version of Selenium RC, which is the result of merging WebDriver and Selenium RC. WebDriver is another tool for writing automated tests of websites but was designed to address some Selenium RC limitations like Same Origin Policy. The difference is that WebDriver controls the browser itself using native methods of the browser and operating system.

is the next version of Selenium RC, which is the result of merging WebDriver and Selenium RC. WebDriver is another tool for writing automated tests of websites but was designed to address some Selenium RC limitations like Same Origin Policy. The difference is that WebDriver controls the browser itself using native methods of the browser and operating system. Selenium 2 supports the WebDriver API and is backward compatible with Selenium RC, which means you can still run tests developed with this version.

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