Please visit Covering IIS for updated information.
That ASP.NET applications are fairly difficult to test may be the understatement of the century. In this article, we're going to show you how to test ASP.NET applications with Selenium, and how to use NCover to review your test coverage.
While it is possible to get 100% coverage for your ASP.NET application using Selenium, we highly recommend that you develop your application in layers and test as many of those layers as possible with a unit testing framework such as NUnit, MSTest, or MbUnit.
I've written a small web application for this article, called MicroFind. The application allows you to enter in a URL, and it will find Microformats embedded within the web page at that URL. Currently it only supports hCard, but more formats could be easily supported. You can download the source for the application and the test suite here. You can learn more about Microformats at http://microformats.org.
Setting Up Selenium
Selenium is a website testing tool written in JavaScript that allows developers to automate interaction with a web browser and create functional tests for their sites. Selenium includes a feature called Selenium Server that makes it possible to programmatically open and close browsers and issue commands to those browsers.
There are several different ways to work with Selenium, but for this example we are going to utilize Selenium Remote Control (Selenium RC). Selenium Remote Control allows developers to write tests with their unit testing framework of choice (in the language of their choice). In our case, we'll be developing our Selenium tests in C# with NUnit.
To get started with Selenium Remote Control, simply download it from the Selenium website at http://selenium-rc.openqa.org/download.jsp and unzip the package to a folder on your computer. We're currently using version 0.9.2. You'll also want to make sure that you have Java version 1.5.0 or higher installed and on your path. I know, I know, we're all .NET zealots here, but Selenium is written in Java and is a great tool, so bite the bullet and download the Java runtime.
Once you have downloaded and unzipped the package, you'll want to look at the folders distributed with Selenium RC. The package includes several language bindings, as well as a copy of Selenium Server. In order to run tests with Selenium, you'll need to have Selenium Server running, so let's do that now. Open a console and browse to the Selenium Server folder from the Selenium RC package, and start the server with the following command:
java -jar selenium-server.jar -interactive
You should see the Selenium Server start up. If you don't, ensure that you have Java correctly installed and look over the Troubleshooting/FAQ section of the Selenium RC site.
Setting Up Your Web Application
This step is fairly self explanatory, but you'll want to have MicroFind installed and running inside of IIS. Make sure that you aren't trying to test within the ASP.NET development server (the one you run inside of Visual Studio). I found that simply copying the MicroFind web application to the IIS wwwroot folder and making that folder an application in the IIS manager got everything set up. Once you have your application configured, access it in your browser and make sure that it is working as you would expect.
Writing Your Tests
If you recall, the Selenium RC package included bindings for several different languages, including .NET. You'll want to make sure that all of the libraries included with the Selenium RC .NET bindings are referenced by your test project.
The first step in writing any Selenium RC test is to open up a browser window. We do that with the following code:
ISelenium browser = new DefaultSelenium("localhost",
4444, "*iexplore", "http://localhost/MicroFind/");
browser.Start();
In the code above we are opening up a new Selenium session with the Selenium Server running on localhost on port 4444 (Selenium's default), and opening a copy of Internet Explorer. The URL given tells Selenium the location of the site we'll be testing. The browser.Start(); line tells the browser to open. I highly recommend that you put this code either in a SetUp method for your test or in another method so that you can easily call it. You'll be using that code before pretty much every test.
Closing the browser is just about as easy as opening it. We simply use the following code:
browser.Stop();
As far as actually testing your site, we'll use methods on the browser object that we created. The API for Selenium RC is fairly large, but the table below covers a few of the basics.
Method | Description |
---|---|
Open(string url) | Opens the url given in the browser. |
Type(string fieldId, string text) | Types text into the field with the id given as fieldId. |
Click(string buttonId) | Clicks the button with the id buttonId. |
WaitForPageToLoad(string timeout) | Waits up to timeout milliseconds for a page to load. |
GetTitle() | Gets the title of the page currently in the browser. |
GetText(string id) | Gets the text in the html element identified by id. |
GetXpathCount(string xpathExpression) | Gets the number of elements that match the XPath expression given. |
There are many more methods available for querying and interacting with the browser, and you can find documentation on them in the doc folder of the .NET Selenium RC bindings.
Now that we've gone over the basics, let's write a simple test. Our test will check that the MicroFind application works correctly in the basic case of just entering a url and having it successfully locate some microformats. We'll use the url http://microformats.org for that, on which I've counted 16 hCards. Our test method looks like this:
[Test]
{ browser.Open("http://localhost/MicroFind/"); browser.Type("urlInput", "http://microformats.org"); browser.Click("analyzeButton"); browser.WaitForPageToLoad("5000"); Assert.AreEqual(16, browser.GetXpathCount("//div[@class='vcard']")); }
The code above should be fairly self-explanatory. The code tells Selenium to point the browser to the MicroFind application, enters http://microformats.org into the url input text box on the page, clicks the analyze button, waits for the application's response, and then asserts the number of hCards in the page using XPath.
The MicroFindSeleniumTests project distributed with this article includes four tests that perform basic checks on the content generated by the application in different scenarios.
Checking Test Coverage
Now that we've written our tests we can check what percentage of the web application they cover. We will, of course, use NCover to do so.
NCover includes the //iis
command line switch. This switch sets up the coverage environment within IIS and restarts the web server. You'll run NCover like this to analyze coverage for your web applications:
NCover.Console.exe nunit-console.exe TestAssembly.dll //iis
When you run NCover in this way, IIS will be restarted to allow NCover to monitor your coverage, and your tests will be run. Once finished, NCover will stop IIS and detach itself. You will need to restart IIS when finished. This is best accomplished by adding the restart command at the end of a build script or manually on the command line:
iisreset /restart
Running NCover in this manner will generate a file named Coverage.Xml that includes your coverage information. You can view this file with NCoverExplorer to review your test coverage. Because ASP.NET generates a large amount of code, it is not uncommon for sequence point coverage to be at 100% while branch point coverage is significantly lower. You'll want to review branch coverage for particular classes to determine what places branch coverage is not up your requirements for code that you have written and what places it is not up to 100% for generated code.
Conclusion
In this article we've set up Selenium Server, written Selenium RC tests against a web application, and checked the test coverage percentage of the web application using NCover. Testing with Selenium is a fairly extensive topic, and this article just scratches the surface. Please don't hesitate to post to the forum or contact the NCover team with any questions you might have about using NCover with Selenium.