November 24, 2014
Hot Topics:

Localizing, unit testing and using AJAX in ASP.NET MVC applications

  • May 26, 2009
  • By Jani Järvinen
  • Send Email »
  • More Articles »

Unit testing MVC applications

One of the great benefits of ASP.NET MVC applications is the ability to better test your code with unit tests. Although it is possible to test regular ASP.NET WebForms applications, this is often considerably more difficult as the application model leads you into mixing user interfaces, data access and logic into same code files and classes. On the other hand, ASP.NET MVC application structure helps creating more natural boundaries for unit tests.

Often, controller classes are the best place to start testing. Since the controller methods do not require any user interface and thus no interactive use to function, they are good candidates for tests. When you start an ASP.NET MVC project, Visual Studio asks whether you want to add a unit testing project to your solution. If you added one, then your solution should look like the one in Figure 3.



Click here for larger image

Figure 3. The default solution structure of an ASP.NET MVC application.

The default template suggests creating one unit test for each controller method, but there is no limit to the number of tests you can write. If you have at least Visual Studio 2008 Professional, then you can use the Test/Run/All Tests in Solution menu command to run all available tests in your solution (Figure 4).



Click here for larger image

Figure 4. Unit test results in Visual Studio.

Writing your tests for ASP.NET MVC applications is similar to writing them for other .NET application types. You can use the Assert class (defined in the Microsoft.VisualStudio.TestTools.UnitTesting namespace) to let Visual Studio know about the results of your tests. For instance, your test might check whether the controller method Customers returns correct data in the ViewData object:

  [TestMethod]
  public void Customers()
  {
    HomeController controller = new HomeController();
    ViewResult result = controller.Customers()
      as ViewResult;
  
    ViewDataDictionary viewData = result.ViewData;
    string tableName = "Customers";
    Assert.AreEqual(tableName, viewData["tableName"]);
  }

When your tests are fast in their execution, running even hundreds of tests goes swiftly. However, since many ASP.NET MVC applications use SQL databases, testing those access routines can take time. Of course, you should test your data access classes (perhaps the models) as well, but often it's more convenient to simulate database access in testing routines with in-memory static data.

One option to implement this is to create a data access interface, which is then implemented by a one class doing the real database access, and another only simulating such access. This simulating class would return static data from memory instead of accessing a real database. With these two implementations, you could use the real one in your application, and the simulating one in your unit tests. For controller tests, this kind of simulated data access is usually enough, and additionally much faster to test.

In fact, such simulating classes are often called mock objects. Mock objects can be used in place of real objects, and thus help in writing your unit tests. Database access is one place where such mock objects are useful, but there are other situations as well. For database access, it is often useful to write your own mock objects, but for other testing tasks, such as those requiring authentication, you might want to use ready-made mock object libraries.

There are several libraries available for .NET, three quite common ones being EasyMock.NET, Moq and Rhino Mocks. All these are open-source solutions, and can be found from the web addresses shown in the Links section. Using mocks depends on the library, but commonly they require you to initialize the framework, after which you can use the mock objects to substitute the real ones.

For instance, if your views are protected so that only authorized users can access them (specified using the Authorize attribute in the controller), then your unit tests might need to construct the proper authentication objects to make the tests succeed. Specifically, this would mean the User and Identity objects. Here is an example of using the Moq library to set up a mock object to help testing views that require authentication:

  using Moq;
  using System.Web;
  using System.Security.Principal;
  ...
  HomeController controller = new HomeController();
  
  var context = new Mock<ControllerContext>();
  var user = new Mock<IPrincipal>();
  var identity = new Mock<IIdentity>();
  context.Setup(
      ctx => ctx.HttpContext.User).Returns(
          user.Object);
  user.Setup(ctx => ctx.Identity).Returns(
      identity.Object);
  identity.Setup(
      id => id.IsAuthenticated).Returns(true);
  identity.Setup(
      id => id.Name).Returns("John Doe");
  
  controller.ControllerContext = context.Object; 

The Moq library relies heavily on C# lambda expressions, giving a modern touch to your unit tests. The framework is also quite simple to learn, provided that you already are at least somewhat familiar with the said lambda expressions.

Note that if you download a testing framework as only binary files, you might run into security issues. This can happen if you simply copy the DLL file(s) into your solution folder and then try to use the framework using a reference. In such a situation, you might notice that Visual Studio reports "Not Executed" while running your tests. If the error details say something like, "Test Run deployment issue: The location of the file or directory 'library.dll' is not trusted", then it is a security issue.

The easiest way to solve this is to go to the DLL file's properties window in Windows Explorer (Alt + double click), and then click the Unblock button. The other option is to add full trust to the assembly with the CasPol utility.





Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Rocket Fuel