Foliotek Developer Blog

Simplifying C# Selenium 2 Tests for ASP.NET WebForms

Our company uses Selenium to automate regression testing of important functionality on our products. One of the products uses ASP.NET Web Forms. Since the ID for controls gets changed from “txtName” to something like “ct100$contentMain$txtName”, we were using the xPath methods (ClickByXPath(), sendKeysByXPath(), anyByXPath(), etc).

The code looked like this:

Previous Test Code

Tester.Driver.clickByXPath(“//input[contains(@id, 'btnSearch')]“);  
Tester.Driver.clickByXPath(“//select[contains(@id, 'drpPrograms')]/option[contains(text(), '" + programName + "')]“);  
Tester.Driver.clickByXPath(“//input[contains(@id, 'rblOption_2')]“);  
Tester.Driver.clickByXPath(“//input[contains(@id, 'cbOption_1')]“);  
Tester.Driver.sendKeysByXPath(“//input[contains(@id, 'txtName')]“, name);


Writing xPath may be enjoyable for some, but for me it got a bit tedious. So, I created some wrapper methods to make this a lot easier to create and read.

New Test Code

SelectDropDownOption(“drpPrograms”, optionName);  
EnterTextBox(“txtName”, name);  

Wrapper Methods

/// Select a RadioButton or an option on a RadioButtonList.  
/// If optionText is specified for a RadioButtonList, this will select that option. Otherwise it works for native RadioButtons  
/// prefix = html filter e.g. "p/" or "tr/td/"  
public void SelectRadio(string radioButtonID, string optionText = "", string prefix = "")  
    string path = "//" + prefix + "input[contains(@id, '" + radioButtonID + "')]";

 if (optionText != "")  
 path += "/ option[contains(text(), '" + optionText + "')]";


/// Select a CheckBox  
/// prefix = html filter e.g. "p/" or "tr/td/"  
public void SelectCheckbox(string checkboxID, string prefix = "")  
    string path = "//" + prefix + "input[contains(@id, '" + checkboxID + "')]";


/// Select an option on a DropDownList  
/// prefix = html filter e.g. "p/" or "tr/td/"  
public void SelectDropDownOption(string dropdownID, string optionText = "", string prefix = "")  
    string path = "//" + prefix + "select[contains(@id, '" + dropdownID + "')]";

 if (optionText != "")  
 path += "/ option[contains(text(), '" + optionText + "')]";


/// Enter text into a TextBox and optionally clear it out first.  
public void EnterTextBox(string txtName, string value, bool clearField = false)  
    Tester.Driver.sendKeysByXPath("//input[contains(@id,'" + txtName + "')]", value, clearField);  

/// Confirm if a condition is true. If it is, output the confirmationMessage.  
public void ConfirmTrue(bool test, string confirmationMessage)  
    Tester.Assert(test, confirmationMessage);

/// Test to see if a control exists on the page.  
/// Control type = input, div, td or whatever  
public bool ControlExists(string controlType, string controlID)  
    string path = "//" + controlType + "[contains(@id,'" + controlID + "')]";  
 return Tester.Driver.anyByXPath(path);

/// Click a Button  
public void ClickButton(string buttonName, string prefix = "")  
    string path = "//" + prefix + "input[contains(@id, '" + buttonName + "')]";


public void ClickByXPath(string xPath)  

public void ClickByLinkText(string linkText)  

For more posts, see Tips and Tricks or Functional Regression Testing

Selenium Regression Testing Part II - Tips and Tricks

In my last post, I talked about how you can use Selenium to do real regressions tests for web applications. It’s a great way to automate testing the real user experience, and not just the backend stuff.

(see Luke’s last post here: Web Application Functional Regression Testing Using Selenium)

That said, Selenium is a relatively new technology, and it’s not without its issues. When building your first test you might find a lot of times where it’s a trial and error process. There are so many different ways to do the same test, it can be overwhelming. Often times, one or more of the ways you try won’t work. I’m going to try to list some of the common problems I ran into and tips I found below.

  • Selenium Commands - waitForElementPresent - this is will block your test proceeding until it finds the identified element.? It checks once a second for 30 seconds.
  • this was the most common way I dealt with ‘ajax’ type interactions where it takes an unknown period of time for something to show up
  • I also use it generally instead of verifyElementPresent ? it does basically the same thing with a little wiggle room
  • mouseDown/mouseUp/mousePressed/click - mostly equivalent, but sometimes you need to match the desired event to a javascript handler
  • try click first.? If it doesn?t work the way you want, move on to mouseDown and so on.
  • waitForFrameToLoad/selectFrame - important if you use iFrames (modal dialog, etc.)
  • the selenium selectors only hit the current frame, otherwise you have to select the correct frame
  • an easy way to get back to the root window is to do selectFrame null
  • type vs. typeKeys - type fills out an input in code ? if it works, use this.? You can use this,and then fire a single typeKeys for the last character if you need an event to be triggered.
  • typeKeys fires the key events on the element - has some idiosyncracies ? certain letters (I?m looking at you,?y?) are reserved to do other special keypresses
  • necessary if you are using a wysiwyg ?designmode? type box instead of a standard input
  • verifyX vs. assertX - if verify fails, the test continues (and is marked as errored).? If assert fails, the test aborts.
  • Usually verify is better, unless one task blocks a future one from functioning correctly
  • runScript vs. Eval vs. Expression - runScript inserts the javascript you provide into the current frame/window.? Useful for those things selenium doesn?t support ? like moving a cursor around and selecting text in a wysiwyg
  • Eval runs javascript in the context of selenium. Handy for complex checks ? use waitForEval (for instance, checking the css background image property of a particular element) - Use this.browserbot.findeElement(?selenium selector?) to find elements the way selenium would
  • Use window.X To access the current frame/window context objects
  • Expression is similar to Eval, but uses Selenium?s custom expression format instead of javascript (but you can combine with javascript by using ?javascript{} - storedVars[?key?] allows you to get to a variable you created with a Selenium ?store? expression
  • selectPopUp - useful for checking stuff in a popup that was initiated
  • Easiest to get by the html title of the popup, but do a ?pause? first to let it load
  • Selenium Selectors and XPath - In general, be as abstract as possible. - Don?t select individual server generated ids (hand crafted html ids are ok if you don’t expect them to change)
  • Don?t select on complicated relationships ( /div[0]/div[2]/a[4] ) ? your html structure will change and you?ll have to maintain it
  • Select links by the simple link=text when possible ? easy to read/maintain, unlikely to change
  • Use //that (any decendant) instead of /this/that where possible
  • .? references ?this? element.? Helps to select something with a particular text: ??//div[@id='publish-private-shares']//p[.='This is pretty cool.']
  • Contains() is useful if you don?t know the exact text (for instance, when an element has multiple css classes):???? //div[@id='pageContent' and contains(@class,'contenteditable') and h2='Goals']/p[1]
  • Selenium RC - While you can use Selenium IDE to create a c# version of your tests ? if you do so, you have two tests to maintain.? You can run your ?selenese? tests directly with RC, too. - JAVAPATHjava.exe ?jar SELENIUMPATHselenium-server.jar ?htmlSuite ?*BROWSER? ?BASESITEURL? ?SUITEFILEPATH? ?RESULTSFILEPATH?
  • I?ve written a simple csharp console project that automatically finds the correct javapath and fires up the test when you run it.? If people ask in the comments, I?ll post it.
  • Last I checked, Chrome and Safari-Windows don?t work.? Chrome is supposed to be fixed in Selenium RC 1.0.4
  • Sauce RC - This is a great UI to help test multiple browsers, but there are a couple of issues - Firefox works, but only in dual window mode
  • IE works, but only in single window mode.
  • The ?timeout? setting implies a default timeout per action in your test, but it is actually the timeout for your entire test run.? Since it defaults to 30 seconds, you?ll probably want to change it, or else your tests will suddenly die for no reason with no explanation/log.

I’m sure there is probably more I’ve forgotten, so leave a comment if you get stuck and I’ll try to help out if I can.

For some helper classes for Selenium 2 with ASP.NET Forms, see the following post: Simplifying C# Selenium 2 Tests for ASP.NET WebForms

Web Application Functional Regression Testing Using Selenium

At Foliotek, we use a rapid development methodology.? Typically, a new item will go from definition through coding to release in a month’s time (bucketed along with other new items for the month).? A bugfix will nearly always be released within a week of the time it was reported.? In fact, we are currently experimenting with a methodology that will allow us to test and deploy new items individually as well – which means that a new (small) item can go from definition to release in as little as a week, too.

Overall, this kind of workflow is great for us, and great for our customers.? We don’t need to wait a year to change something to make our product more compelling, and customers don’t have to wait a year to get something they want implemented.? We also avoid the shock of suddenly introducing a year’s worth of development to all our customers all at once – a handful of minor changes every month (or week) is much easier to cope with.

However, it also means that Foliotek is never exactly the same as it was the week before.? Every time something changes, there is some risk that something breaks.?? We handle this risk in two ways:

  1. We test extremely thoroughly
  2. We fix any problems that arise within about a week (severe problems usually the same day)

At first, we did all testing manually.? This is the best way to test, assuming you have enough good testers with enough time to do it well.? Good testers can’t be just anyone – they have to have a thorough knowledge of how the system should work,they have to care that it does work perfectly,and they have to have a feel for how they might try to break things.? Having enough people like this with enough time to do testing is expensive.

Over time two related things happened.? One was that we added more developers to the project, and started building more faster.? Two was that the system was growing bigger and more complex.

As more people developed on it and the system grew more complex, our testing needs grew exponentially.? The rise in complexity and people developing led to much, much more potential for side-effects – problems where one change affects a different (but subtly related) subsystem.? Side-effects by their nature are impossible to predict.? The only way to catch them was to test EVERYTHING any time ANYTHING changed.

We didn’t have enough experienced testers to do that every month (new development release) let alone every week (bugfix release).

To deal with that, we started by writing a manual regression test script to run through each week.? While this didn’t free up any time overall – it did mean that once the test was written well, anyone could execute it.? This was doable, because we had interns who had to be around to help handle support calls anyways – and they were only intermittently busy.? In their free time they could execute the tests.

Another route we could have gone would have been to write automated unit tests ( Basically, these are tiny contracts the developers would write that say something like “calling the Add function on the User class with name Luke will result in the User database table having a new row with name Luke”.? Each time the project is built, the contracts are verified.? This is great for projects like code libraries and APIs where the product of the project IS the result of each function.? For a web application, though, the product is the complex interaction of functions and how they produce an on screen behavior.? There are lots of ways that the individual functions could all be correct and the behavior still fails.? It is also very difficult to impossible to test client-side parts of a web application – javascript, AJAX, CSS, etc.? Unit testing would cost a non trivial amount (building and maintaining the tests) for a trivial gain.

Eventually, we discovered the Selenium project ( The idea of Selenium is basically to take our manual regression test scripts, and create them such that a computer can automatically run the tests in a browser (pretty much) just like a human tester would.? This allows us to greatly expand our regression test coverage, and run it for every single change we make and release.

Here are the Selenium tools we use and what we use them for:

  • Selenium IDE ( : A Firefox plugin that lets you quickly create tests using a ‘record’ function that builds it out of your clicks, lets you manually edit to make your tests more complex, and runs them in Firefox.
  • Selenium RC ( A java application that will take the tests you create with Selenium IDE, and run them in multiple browsers (firefox, ie, chrome, etc).? It runs from the command line, so its fairly easy to automate test runs into build actions/etc as well.
  • Sauce RC ( A fork of RC that adds a web ui on top of the command line interface.? It’s useful for quickly debugging tests that don’t execute properly in non-firefox browsers.? It also integrates with SauceLabs – a service that lets you run your tests in the cloud on multiple operating systems and browsers (for a fee).
  • BrowserMob ( An online service that will take your selenium scripts and use them to generate real user traffic on your site.? Essentially, it spawns off as many real machines and instances of FireFox at once to run your test – each just as you would do locally – for a fee.? It costs less than $10 to test up to 25 “real browser users” – which actually can map to many more users than that since the automated test doesn’t have to think between clicks.? It gets expensive quickly to test more users than that.

Selenium is a huge boon for us.? We took the manual tests that would occupy a tester for as much as a day, and made it possible to run those same tests with minimal interaction in a half hour or less.? We’ll be able to cover more test cases, and run it more – even running them as development occurs to catch issues earlier.

In my next post, I’ll talk about the details of how you build tests, run them, maintain them, etc. with the tools mentioned above. See it here: Selenium Tips and Tricks

Also, for Selenium 2 with ASP.NET Web Forms, see Simplifying C# Selenium 2 Tests for ASP.NET WebForms