Mocking an ASP.NET MVC controller using NSubstitute

Mocking an ASP.NET MVC controller using NSubstitute

I’ve found that the concept of mocking confuses some developers. It’s probably due to the fact that they usually experience the idea formally, at first—in the context of a mocking framework. Some of these frameworks are very powerful—and fairly complex.

However, The basic idea is quite simple.

Take the following controller

public class NotificationController : Controller
{
    private readonly ICourseService courseService;
    private readonly IMailService mailService;
    private readonly IUserService userService;

    public NotificationController(IUserService userService, 
        ICourseService courseService, IMailService mailService)
    {
        this.userService = userService;
        this.courseService = courseService;
        this.mailService = mailService;
    }

    public ActionResult Index(long userId, int courseId)
    {
        User user = this.userService.RetrieveUser(userId);
        Course course = this.courseService.RetrieveCourse(courseId);

        var message = new Message
                          {
                              ToEmail = user.Email,
                              Subject = string.Format(
                                  "Course {0} registration confirmation", courseId),
                              Body = string.Format(
                                  @"Your place on course '{0}' ({1}) has been 
                                      reserved.", 
                                  course.Title, course.Id)
                          };

        this.mailService.Send(message);

        return this.View("Index", course);
    }
}

This controller has an Index action method that notifies users, via e-mail, that they have been registered for a training course–before displaying a view saying that the course confirmation has been sent.

I use dependency injection (e.g. Ninject) to pass the following services into the controller

  • an IUserService object that allows a user to be retrieved from an external (web) service using an ID
  • an ICourseService object that allows a training course to be retrieved from an external (web) service using an ID
  • an IMailService object that sends an e-mail Message to the user

Injecting these objects into the controller is a best practice as I can test the controller in isolation of these external services. However, the controller requires some kind of IUserService, ICourseService and IMailService—so these need to be faked (mocked).

To fake an IUserService object, for example, I can create the following class

public class FakeUserService : IUserService
{
    public User RetrieveUser(long userId)
    {
        return new User { Id = 1, FirstName = "John", LastName = "Doe", 
                          Email = "John.Doe@learningtree.com" };
    }
}

An instance of FakeUserService can them be passed into NotificationController for testing. The same kind of fake can be created for the remaining services.

The problem with this approach is that we end up with a lot of extra classes cluttering up our solution—and they need to be maintained. Ugh.

This is where we can turn to a mocking framework. Mocking frameworks create these fake objects behind the scenes—implementing just enough functionality to meet the needs of our tests.

Let’s look at an example of using a mocking framework in a unit test. My mocking framework of choice used to be FakeItEasy, but I got fed up of paying what I’ve heard referred to as “the lambda tax”. For example, faking the IUserService in FakeItEasy might involve the following code

var userService = A.Fake<IUserService>();
A.CallTo(() => userService.RetrieveUser(A<long>._)).Returns(user);

The () => in the parameter to CallTo isn’t, to my mind, the most intuitive piece of code.

I now tend to use NSubstitute. In NSubstitute, faking this the IUserService would involve

var userService = Substitute.For<IUserService>();
userService.RetrieveUser(Arg.Any<long>()).Returns(user);

Not a lambda in sight. Don’t get me wrong—FakeItEasy is an excellent framework. I’m just a little OCD.

So, my entire test method, utilizing NSubstitute to create the fakes, would be

[TestMethod]
public void WhenNotificationActionCalled_CorrectMessageIsSent()
{
    /* Arrange */

    var userService = Substitute.For<IUserService>();

    var user = new User { Id = 1, FirstName = "John", LastName = "Doe", 
                          Email = "John.Doe@learningtree.com" };
    userService.RetrieveUser(Arg.Any<long>()).Returns(user);

    var course = new Course { Id = 511, 
                              Title = ".NET Best Practices and Design Patterns" };
    var courseService = Substitute.For<ICourseService>();
    courseService.RetrieveCourse(511).Returns(course);

    var mailService = Substitute.For<IMailService>();

    var notificationController = 
        new NotificationController(userService, courseService, mailService);

    var message = new Message
                      {
                          ToEmail = user.Email,
                          Subject = 
                              string.Format("Course {0} registration confirmation", 
                                  course.Id),
                          Body = 
                              string.Format(
                                  @"Your place on course '{0}' ({1}) has been 
                                      reserved.", 
                                  course.Title, course.Id)
                      };

    /* Act */

    var viewResult = (ViewResult)notificationController.Index(user.Id, course.Id);

    /* Assert */

    mailService.Received().Send(Arg.Is<Message>(x => x.ToEmail == user.Email));
    mailService.Received().Send(Arg.Is<Message>(x => 
        x.Subject == 
            string.Format("Course {0} registration confirmation", course.Id)));
    mailService.Received().Send(Arg.Is<Message>(x => 
        x.Body == 
            string.Format("Your place on course '{0}' ({1}) has been reserved.", 
                course.Title, course.Id)));

    Assert.AreEqual("Index", viewResult.ViewName);

    var model = (Course)viewResult.Model;

    Assert.AreEqual(511, model.Id);
    Assert.AreEqual(".NET Best Practices and Design Patterns", model.Title);
}

In the “Arrange” section, I just set up the fakes and have them return the required values. Then I create an instance of the NotificationController, injecting the fakes into it. Finally, I create the Message instance I expect to be sent.

The “Act” section just executes the controller’s Index action method.

Finally, in the “Assert” section, I check that the controller passed the correct parameter to the IMailService.Send method. In addition, I check that the correct view and model were passed back to the ASP.NET MVC framework.

This has been a brief introduction to mocking an ASP.NET MVC controller using NSubstitute. If you would like to learn more about .NET best practices, or the ASP.NET MVC framework, Learning Tree has a range of courses that might interest you, including:

image sources

  • Mocking an ASP.NET MVC controller using NSubstitute: Andrew Tait

Type to search blog.learningtree.com

Do you mean "" ?

Sorry, no results were found for your query.

Please check your spelling and try your search again.