Back to top

Mocking users in ASP.NET MVC 5

So historically unit testing has been a constant non-starter for me. It seems every time I start to write unit tests (whether it’s in an attempt to do some TDD, or just trying produce unit tests for an existing piece of code), I struggle to get over the hump of dependencies that I’ve incidentally placed in my way without even thinking.

Things as simple as getting the current user’s ID using User.Identity.GetUserId() seem harmless, until you realise that in your test the User object will be null.

When dealing with dependencies in the code that you are testing, a common method is to replace these dependencies with a mock. For example, say you have a service which calls off to an external API to get some data; in your test code, you could mock (aka “fake”) that service to just return some fake data rather than calling to the external API.

You can do this mocking quite simply yourself, or you can look at using a library for doing so, such as Moq. For simple cases, or when you’re just starting out and trying to understand how it all comes together, doing your own mocks manually is a great way to go. Additionally, Moq doesn’t allow you to mock static or extension methods (well apparently you can, but it’s complicated and for reasons which I’m still investigating to understand why, it’s not desired). As a result, the above call to User.Identity.GetUserId() needs to be mocked manually.

Now it’s worth mentioning here, too, that some of these trickier implementation issues have been made simpler in ASP.NET Core, due to changes to the way the Identity has been implementing with testability in mind from the start.

Mocking a User Identity

My solution was to extract out the calls to get the User ID from the controller to an interface, so that I can mock the implementation of that for my tests. I decided to keep it simple for my solution, given that I’m really not using anything other than the user’s ID in my code that I’m testing. If you need to claims and other data from the user identity object, you may need to look for more extensive solutions.

First I create an interface which for now just needs one method, for getting the User ID. I will pass in the User object (which may be null in the case of testing):

IUserService.cs:

using System.Security.Principal;

namespace MockingSample.Data.Interfaces
{
    public interface IUserService
    {
        string GetUserId(IPrincipal user);
    }
}

Next I create an implementation of this which uses the Identity extension method:

IdentityUserService.cs:

using MockingSample.Data.Interfaces;
using Microsoft.AspNet.Identity;
using System.Security.Principal;

namespace MockingSample.Data.Services
{
    public class IdentityUserService : IUserService
    {
        public string GetUserId(IPrincipal user)
        {
            if (user == null)
                return string.Empty;

            return user.Identity.GetUserId();
        }
    }
}

Now in the controller I can call this rather than directly calling on User.Identity.GetUserId(). I’m using constructor injection to get my dependency into the class, and the project is using StructureMap as it’s IoC/DI container for this injection:

HomeController.cs:

using System.Web.Mvc;
using MockingSample.Data.Interfaces;

namespace MockingSample.Controllers
{

    public class HomeController : Controller
    {
        private readonly IUserService _userService;

        public HomeController(IUserService userService)
        {
            _userService = userService;
        }

        public ActionResult Index()
        {
            var userId = _userService.GetUserId(User);

            // Do something with the userId

            return View("Index");
        }
}

Mocking the service

Now in my test project, I create a new implementation of the IUserService interface to mock the data:

MockUserService.cs:

using System;
using System.Security.Principal;

namespace MockingSample.Tests.Mocks
{
    public class MockUserService : IUserService
    {
        public string GetUserId(IPrincipal user)
        {
            return Guid.NewGuid().ToString();
        }
    }
}

So all I’m doing is returning a new Guid for the user ID. If I needed to know exactly what it was going to be for deeper testing, I could set it to some “known” value. For my tests, though, what the value is doesn’t matter.

Now in my test, I can inject an object of this class into my Home controller:

[TestMethod]
public void HomeControllerSelectsTipsView()
{
    // Arrange
    MockUserService userService = new MockUserService();
    HomeController controller = new HomeController(userService);


    // Act
    ViewResult result = controller.Index() as ViewResult;

    // Assert
    Assert.AreEqual("Index", result.ViewName);
}   

Running this test now succeeds, whereas previously I was getting an object reference error due to the User object being null.

I’ve done a similar thing now to also mock out some calls to an external API that I use, because the provider for the external calls that I wrote years ago is all using static methods - so I simply created a wrapper class that calls those static methods, and for the mock class I can just return some test data that I can rely on for assertions.

I hope this helps someone else as I did find it quite a struggling to come upon the “right” solution for my situation, and as we know there are many ways to skin a cat - if anything above looks wrong to you, though, do let me know as I’d appreciate the guidance on my path to “proper testing”!