Testing Rendered HTML in ASP.NET MVC3

ASP.NET applications are still difficult to write automated tests against. Other languages (notably Ruby on Rails) have powerful mechanisms to perform not only unit-level testing, but also integration testing: fetching a set of webpages, performing postbacks, and verifying the HTML from the responses along the way.

MVC3 is partially testable: you can create controllers and request views, even pull items out of the ViewBag. That’s great, but for many applications, it’s not enough; you want to be able to actually read the underlying HTML and check for the presence or absense of certain HTML content.

Thankfully, there is an answer. It’s not simple, but it is relatively straight-forward: deploy your debug directory of your web application onto IIS, and use a .NET conversion of HtmlUnit (a GUI-less browser written in Java) to run on IKVM, a .NET implementation of the JRE.

Credit for this amazing solution goes to Steve Sanderson, who documented the process (and built the binaries) on his blog. Essentially, you need to:

  • Deploy your debug environment into IIS (giving you the benefit of seeing real IIS errors that don’t appear in Casini)
  • Download the HtmlUnit and IKVM binaries
  • Add all the appropriate references to your test project
  • Compile, execute, and rejoice

Steve’s page does a great job of xplaining all the steps; just note that he has a link to the IKVM and HtmlUnit binaries at the end of his post (so you don’t need to build them yourself).

Once you have your app deployed, testing can be as simple as:


[TestMethod]
public void RequestingSecureUrlRedirectsToLogOn() {
WebClient webClient = new WebClient();
HtmlPage page = (HtmlPage)webClient.getPage("http://localhost/some/secure/action");
WebResponse response = page.getWebResponse();
Assert.IsTrue(response.getRequestUrl().toString().EndsWith("/Account/LogOn"));
}

Run your tests (Visual Studio test framework in my case), and, tada! More complicated tests are possible (filling out forms, clicking buttons, checking response HTML), all though the HtmlPage API. For example, we could have extended that test to include:


((HtmlInput)page.getElementById("UserName")).setValueAttribute("bob");
((HtmlInput)page.getElementById("Password")).setValueAttribute("invalid");
HtmlPage resultsPage = (HtmlPage)loginPage.getElementById("submit").click();

string content = resultPage.asXml();
Assert.IsTrue(content.Contains("Login was unsuccessful."));

In this case, we filled in the UserName and Password fields, clicked Submit, and checked the HTML of the resulting page — that it contained an error message.

Pretty slick stuff. I highly recommend it if unit testing is something you prioritize. The potential for integration testing is pretty awesome.

About Ashiq Alibhai, PMP

Ashiq has been coding C# since 2005. A desktop, web, and RIA application developer, he's touched ASP.NET MVC, ActiveRecord, Silverlight, NUnit, and all kinds of exciting .NET technologies. He started C# City in order to accelerate his .NET learning.
This entry was posted in Libraries, Web and tagged , , , , . Bookmark the permalink.

2 Responses to Testing Rendered HTML in ASP.NET MVC3

  1. I have ASP.NET MVC Project. My Views include content, which downloads via AJAX.
    var webClient = new WebClient(BrowserVersion.FIREFOX_17)
    {
    JavaScriptEnabled = true,
    ThrowExceptionOnScriptError = true,
    AjaxController = new NicelyResynchronizingAjaxController()
    };

    var completePage = (HtmlPage)webClient.GetPage(“http://mysite/index”);

    webClient.WaitForBackgroundJavaScript(20000);

    var page = completePage.DocumentElement.AsXml();

    This my final code, but AJAX is not executes. I get page without content. What should I do?

  2. Ashiq Alibhai, PMP says:

    @massimo have you tried other browser versions?

    You can ask at the HtmlUnit mailing list instead. They might have some good ideas. (I don’t know, sorry.)

    I have seen some of my functional (HtmlUnit) tests sporadically fail (the ones that call AJAX/Javascript/jQuery stuff). I haven’t yet figured out why.

Leave a Reply

Your email address will not be published. Required fields are marked *