Unit Testing ASP.Net MVC 5 Controllers using Rhino Mocks

Unit Testing ASP.Net MVC Controllers is not as straight-forward as you may thing, because as you get started, you face questions such as: how to create an HttpContext, an HttpContextBase, should you prefer mocking, and which mocking framework, etc.

After a day of googling and tinkering, I finally came up with a working solution using Rhino.Mocks and MvcContrib, both downloaded via nuget. To analyze Owin black magic, I used the source code repositories of Katana on Codeplex and symbolsource.

[TestClass()]
public class HomeIndexControllerTests
{
  [TestMethod()]
  public void HomeIndexTest()
  {

The authentication routine uses async calls, such as FindByNameAsync(). I tried to declare the test method as public async Task, but after starting the test, the IDE claimed it’s busy, but did not execute the test.

Without Task.Run(), the async method would fail throwing an AggregateException.

I found the work-around to encapsulate the whole test inside a Task.Run():

    Task.Run(() =>
    {
      var builder = new TestControllerBuilder();

First, we mock the ApplicationUserManager

      var us = MockRepository.GenerateStub<IUserStore<AppUser>>();
      var aum = MockRepository.GenerateStub<ApplicationUserManager>(us);

My class for storing users in the user database is called AppUser. The variable appuser is set to null for unauthenticated requests, and contains a valid object if authenticated:

      AppUser appuser = null;
      //appuser = new AppUser { .... values .... };  // uncomment for authenticated request

These stubs return the defined user object:

      us.Stub(u => u.FindByNameAsync(""))
        .IgnoreArguments()
        .Return(Task.FromResult(appuser));
      aum.Stub(m => m.FindByNameAsync((ClaimsIdentity)null, ""))
        .IgnoreArguments()
        .Return(Task.FromResult(appuser));

Create the Owin context and register the user manager:

      var owin = new OwinContext();
      owin.Set(aum);

Use the builder to create the controller under test:

      var controller = builder.CreateController<C.Home.IndexController>();

To test unauthenticated requests, we check whether the class or the method have an [Authorize] attribute

      if (appuser == null)
      {
        var type = controller.GetType();
        var attributes = type.GetCustomAttributes(typeof(AuthorizeAttribute), true);
        var methodInfo = type.GetMethod("Execute" 
          /*, new Type[] { ....parameter types.... } */
        );
        var methodAttributes = methodInfo.GetCustomAttributes(typeof(AuthorizeAttribute), true);
        Assert.IsFalse(attributes.Any() || methodAttributes.Any(), "Unauthorized request not allowed");
      }

Next, we wire up the HttpContext and Owin, and set the request’s cookies:

      var context = controller.HttpContext; 
      // the context is already mocked, so we can stub() it

      var dict = new Dictionary<object, object>();
      dict.Add("owin.Environment", owin.Environment);
      context.Stub(c => c.Items).Return(dict);
      var request = controller.Request;
      request.Stub(r => r.Cookies).Return(new HttpCookieCollection());

Next, we create a principal from the user object (see here for setting the name claim)

      var user = new GenericPrincipal(
        new ClaimsIdentity(
          new Claim[] { 
            new Claim(ClaimTypes.Name, appuser == null ? "" : appuser.UserName) }),
        new string[0]);
      context.User = user;

Then we create a fake HttpContext which matches the mocked HttpContextBase object created above:

      HttpContext.Current = new HttpContext(
        new HttpRequest("", "http://tempuri.org", ""),
        new HttpResponse(new StringWriter())
      );
      HttpContext.Current.Items["owin.Environment"] = owin.Environment;
      if (appuser != null)
        HttpContext.Current.User = user;

We are now ready to execute the controller method

      builder.InitializeController(controller);
      var result = controller.Execute();

And check the results: if the request is successful, the result is typically a ViewResult.

      Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
      Assert.IsInstanceOfType(result, typeof(ViewResult));

We can now test the result values, and end the Task definition:

    }).GetAwaiter().GetResult();
  }
}

 

Configuring JMeter for ASP.Net Sites

Comparing different web sites running the same ASP.Net application, my idea was to use JMeter to perform a couple of requests and display the execution times for the requests per site.

A web test is called Test Plan in JMeter, and in the most basic version looks like this:

The test plan has a Thread Group which defines how often a sequence of steps is performed, and how many threads are used to execute the sequence.

Use a HTTP Request Defaults configuration element to define server name, port number and other connection parameters.

Under the Simple Controller (under Logic Controllers) to contain the sequence of steps, consisting of HTTP Request or HTTP Request HTTPClient elements (under the Samplers menu). Each of them contains the URL Path (everything after the host name) and optionally a couple of parameters.

Next, add a couple of Listeners, such as Summary Report, View Results Tree and View Results in Table to display the requests’ performance data.

While this would be sufficient for non-ASP.Net web sites, ASP.Net requires a couple more elements.

First, the HTTP Cookie Manager is required to store the ASP.Net session cookie. Simply add it as config element.

Next, the various hidden variables of ASP.Net need to be parsed and posted. For example, a POST requires that the __VIEWSTATE variable is posted as well, otherwise ASP.Net would not be able to perform its magic.

To achieve this, we need a Regular Expression Extractor (post processor) to extract the value of the __VIEWSTATE variable in the original page:

Set the reference name to viewState (or any name you prefer and find reasonable), and the regular expression to

name="__VIEWSTATE" id="__VIEWSTATE" value="(.+?)"

In the login example below, we must first GET the login page, the RegEx extractor will retrieve the view state, which is then posted using the ${viewState} macro notation to pass its value on:

If you use the Ajax Control Toolkit, you may also need to pass the ScriptManager’s hidden value. Hit F12 in your browser, enable request logging (Net, All in Firefox; Network in Chrome), and find the posted value in the Request data.

Thanks to the pages that helped me with the information I needed: Technically Works, and a couple of answers on StackOverflow.