The agile development community has struggled for years with an Array
Of solutions for automated testing solutions for web development.
Nunitasp is a good way to unit test server side ASP. NET Code, especially
Now that it doesn't require XHTML compliant pages, but it can't handle
Client side scripting and Ajax is exploding in popularity. Several
Tools have used COM (must die) to drive Internet Explorer (IE)
Varying degrees of success. My personal experience is that the IE COM
API is too Byzantine and flat out flaky. Besides the flakiness, Firefox
And other browsers are gaining in popularity so the IE only testing
Might not cut it anymore.
Enter the selenium
Project. The developers of selenium had the brilliant, but in
Retrospect painfully obvious, idea to use JavaScript inside a browser
Drive the Web Testing. Presto, automatic testing for Web Applications
That can test Client Side JavaScript and multiple browser engines. In
Its original incarnation selenium ran fit style test tables inside a web
Browser. Recently, selenium remote control
Has been released to that allow the core JavaScript Engine to be driven
Through API's for. net, Java, Ruby, or Python. The fit style table
Runner is perfectly functional, but for us it's very convenient to use
The selenium RC. Net wrapper. So far I'm pleasantly surprised by how
Easy it is to use the. NET wrapper.
Sample Test
The API libraries communicate with the selenium server, a Java
Executable that can start and stop any supported browser and send
Testing commands to the browser. the. NET callable wrapper works
Sending HTTP messages to the selenium server that controls a browser.
The first step is to start up the selenium server from a command prompt.
java -jar server\selenium-server.jar -interactive
The next step was to create a simple HTML page with a textbox that changes values when a button is clicked:
<script language=javascript src=prototype-1.4.0.js></script>
<title>Selenium Target Page</title>
<script id=clientEventHandlersJS language=javascript>
<!--
function button1_onclick() {
$('text1').value = "Goodbye"; // Using the Prototype library
}
//-->
</script>
<body>
<form name="form1">
<input id="button1" type=button onclick="return button1_onclick()" value="click me"/>
<input id="text1" type=text value="Hello"/>
<select testid="select1" >
<option value="1">North</option>
<option value="2" selected=true>West</option>
<option value="3">South</option>
<option value="4">East</option>
</select>
</form>
</body>
Next I wrote a little nunit test fixture class to run tests against
The web page. The key object is the defaultselenium class that is
Created in the setup () method:
/// <param name="serverHost">the host name on which the /// Selenium Server resides</param>
/// <param name="serverPort">the port on which the /// Selenium Server is listening</param>
/// <param name="browserString">the command string used /// to launch the browser, e.g. "*firefox", "*iexplore" /// or "c:\\program files\\internet explorer\\iexplore.exe"</param>
/// <param name="browserURL">the starting URL including /// just a domain name. We'll start the browser pointing at /// the Selenium resources on this URL,
/// e.g. "http://www.google.com" would send the browser to /// "http://www.google.com/selenium-server/SeleneseRunner.html"</param>
public DefaultSelenium(String serverHost, int serverPort, String browserString, String browserURL)
{
this.commandProcessor = new HttpCommandProcessor(serverHost, serverPort, browserString, browserURL);
}
using System;
using NUnit.Framework;
using Selenium;
namespace SeleniumTarget
{
[TestFixture]
public class WebPageTester
{
DefaultSelenium selenium;
[SetUp]
public void SetUp()
{
// 4444 is the default port for the Selenium Server
selenium = new DefaultSelenium("localhost", 4444, "*iexplore", "http://localhost");
selenium.Start();
}
[TearDown]
public void TearDown()
{
// Make sure the Selenium environment is cleaned up after each test
selenium.Stop();
}
[Test]
public void CheckTheTitle()
{
selenium.Open("http://localhost/SeleniumTarget/TestPage1.htm");
Assert.AreEqual("Selenium Target Page",
selenium.GetTitle(),
"Check the title of the browser");
}
[Test]
public void ClickButton1ChangesText1FromHelloToGoodbye()
{
selenium.Open("http://localhost/SeleniumTarget/TestPage1.htm");
Assert.AreEqual("Hello",
selenium.GetValue("text1"),
"Initial Value");
selenium.Click("button1");
Assert.AreEqual("Goodbye",
selenium.GetValue("text1"),
"Value after clicking button1");
}
/// <summary>
/// Check that the options of a <select></select> element are
/// as expected. Finds the <select> element by using an xpath expression
/// </summary>
[Test]
public void Select1Values()
{
selenium.Open("http://localhost/SeleniumTarget/TestPage1.htm");
string locator = "xpath=//select[@testid='select1']";
string[] options = selenium.GetSelectOptions(locator);
Assert.AreEqual(new string[] {"North", "West", "South", "East"},
options,
"Values in the select1 dropdown");
}
}
}
It's a trivial example, but it's a start.
What I don't know-
- What's the best way to handle the selenium server process? How do
You guarantee it's up when you start your tests? I'm thinking some kind
Of Windows Service wrapper
- How do you integrate Selenium with cruisecontrol. Net to get it
Your continuous integration strategy? I can't find much on the Web
About this yet. You can run selenium from nunit for developer testing,
But that isn't a very desirable answer from a tester's perspective.
A couple of reasons, our thinking is to wrap the selenium manipulation
Inside a fitnesse dofixture. We already know how to integrate fitnesse tests within a CC. Net build
And it's convenient to run all the tests together. We're also hoping
That the dofixture tests will be easier to understand and that we can
Hide some of the web page details behind the fixture.
Other tools
We're re looking primarily at selenium, But we're re also considering watir (Ruby Based Tool) and Sahi
(I don't know much about it, but it looks strong). One of our
Colleagues is experimenting with a ruby based DSL for testing another
Web product using watir as the core that looks promising. I 've also
Been playing with the ruby driver for selenium with an eye
Creating a testing DSL for our application.