Mocking and Dependency Injection in ASP.NET MVC

Here is the situation, my controller constructors take multiple interfaces as parameters.  I do this in order to use constructor injection which allows me to inject the controllers with mocked objects in my unit tests.

For example, my AccountController takes IEmailService, IFormsAuthentication and MembershipProvider (abstract class) as parameters.

During my testing, I want to mock the email, authentication and membership calls.  For example when the user calls FormsAuthentication.Login, I don’t really care if actual call succeeded but rather that my login action works appropriately in the case FormstAuthentication.Login succeeds (or fails).  I just want to mock that call.

I started off creating a few tests and slowly they have grown to several.  There was a lot of repeated code in my unit tests and to be a good citizen of the DRY universe, I needed to refactor the code.

For IoC, I initially started with StructureMap but now I am using Ninject

I created this module to bind my interfaces to mocked instances.  It looks like this:

internal class TestModule : StandardModule
{
    public override void Load()
    {
        Bind<IEmailService>()
            .ToConstant(MyMocks.MockEmailService.Object);
        
        Bind<IFormsAuthentication>()
            .ToConstant(MyMocks.MockFormsAuthentication.Object);
        
        Bind<MembershipProvider>()
            .ToConstant(MyMocks.MockMembershipProvider.Object);
        
        Bind<IContactListService>()
            .ToConstant(MyMocks.MockContactListService.Object);
    }
}

Notice that I bind the interfaces to actual instances and not classes.  These instances are declared in a global static class that will be accessed from my unit tests.  As you can tell from the name, they are all mocked objects (I am using Moq).  Here is how the MockEmailService looks (all the others are declared the same way):

internal static class MyMocks
{
    private static Mock<IEmailService> _mockEmailService;
    public static Mock<IEmailService> MockEmailService
    {
        get
        {
            _mockEmailService = _mockEmailService ?? new Mock<IEmailService>();
            return _mockEmailService;
        }
    }

 

So all this is good to setup Ninject and create my mocks.  Now I want to easily and generically create a controller, so I can quickly create unit tests.  In order to do that, I created a TestControllerFactory class that basically creates a controller with all the appropriate dependencies injected.

   1: internal static class TestControllerFactory
   2: {
   3:     private static IKernel _kernel;
   4:     public static IKernel Kernel
   5:     {
   6:         get
   7:         {
   8:             if (_kernel == null)
   9:             {
  10:                 var modules = new IModule[] { new TestModule() };
  11:                 _kernel = new StandardKernel(modules);
  12:             }
  13:             return _kernel;
  14:         }
  15:         private set
  16:         {
  17:             _kernel = value;
  18:         }
  19:     }
  20:  
  21:     public static T GetControllerWithFakeContext<T>(string httpMethod) 
  22:         where T : Controller
  23:     {
  24:         var con = Kernel.Get<T>();
  25:         con.SetFakeControllerContext();
  26:         if (con != null) con.Request.SetHttpMethodResult(httpMethod);
  27:         return con;
  28:     }
  29:  
  30: }

In line #10, I use the TestModule class mentioned above to setup the Ninject Kernel.  In lines #21 to #28, I create an instance of T which must be of type Controller from the Kernel which will automatically create the Controller with all the mocked objects.  In line #25 and #26, I just set a fake/mocked context and the Http Method for the request (more info here).

Now my unit tests are very clean and easy to setup.    Using MbUnit as my unit test framework, here is a unit tests that tests the reset password functionality.

   1: [Test]
   2: public void ResetPasswordQuestion_Should_Send_Email_On_Success()
   3: {
   4:     var newpassword = "newpassword";
   5:     MyMocks.MockMembershipProvider
   6:          .Expect(p => p.ResetPassword(username, answer))
   7:          .Returns(newpassword);
   8:     MyMocks.MockEmailService
   9:          .Expect(m => m.SendPasswordReset(username, newpassword));
  10:  
  11:     var ac = TestControllerFactory
  12:                 .GetControllerWithFakeContext<AccountController>("POST");
  13:  
  14:     var results = ac.ResetPasswordQuestion(username, question, answer);
  15:     //write some asserts in here to make sure things worked
  16:  
  17:     //verify all mocks
  18:     MyMocks.MockMembershipProvider.VerifyAll();
  19:     MyMocks.MockEmailService.VerifyAll();
  20: }

Line #5: I mock the ResetPassword call on the membership provider and tell it to return the new password

Line #8: I mock the SendPasswordReset method on the email service

Line #11: Get an instance of AccountController from the Ninject Kernel

I just write some code to make sure the expected results took place and that my mocks were properly exercised and that’s pretty much it.  No need to have an SMTP server working to test this, no need to have a database, no need to have an authentication method, no need to implement the interfaces or write dummy methods.

I am like a kid in a candy store with all these things: mocking, dependency injection, inversion of control, unit testing…  I am loving it.

So what do you think?  Is this a good way to go about it?  Is there a better way and what is it?

Unit Test Linq to Sql in ASP.Net MVC with Moq

I have just spent the entire day playing with Moq to unit test an asp.net mvc application I am working with. All I wanted to do is test a “create” method that simply adds a record to the database. So here it goes.

1. I created a Mock Http context to be used by my controller. I modified the Moq version of the MvcMockHelpers class from Scott Hanselman and added two more methods to mock an authenticated user

public static HttpContextBase FakeAuthenticatedHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var user = new Mock<IPrincipal>();
var identity = new Mock<IIdentity>();

context.Expect(ctx => ctx.Request).Returns(request.Object);
context.Expect(ctx => ctx.Response).Returns(response.Object);
context.Expect(ctx => ctx.Session).Returns(session.Object);
context.Expect(ctx => ctx.Server).Returns(server.Object);
context.Expect(ctx => ctx.User).Returns(user.Object);
user.Expect(ctx => ctx.Identity).Returns(identity.Object);
identity.Expect(id => id.IsAuthenticated).Returns(true);
identity.Expect(id => id.Name).Returns("test"); 
    return context.Object;
}
public static void
SetFakeAuthenticatedControllerContext(this Controller controller)
{
var httpContext = FakeAuthenticatedHttpContext();
ControllerContext context =                  
new ControllerContext(
new RequestContext(httpContext,
new RouteData()), controller);
controller.ControllerContext = context;
}

Note that the identity.Name returns “test” which is the username of an existing user in the database. If I don’t do that then the MembershipProvider.GetUser method will fail.

2. I added a couple of properties to my test class (MessageControllerTest) to make it easy for me to access the controller and view engine in all the test methods

private FakeViewEngine _fakeViewEngine;
public FakeViewEngine FakeViewEngine
{
get
    {
if (_fakeViewEngine == null)

              _fakeViewEngine = new FakeViewEngine();
return _fakeViewEngine;
}
}

private MessageController authenticatedController;
private MessageController AuthenticatedController
{
get
    {
if (authenticatedController == null)
{
authenticatedController = new MessageController();
authenticatedController.ViewEngine = FakeViewEngine;
authenticatedController.SetFakeAuthenticatedControllerContext();
}
return authenticatedController;
}
}

3. I created my test method which is going to call a Create method in my MessageController and pass it a string.

[TestMethod]
public void Create_Message_Test()
{
AuthenticatedController.Create("This is a test message");

//verify
    Assert.AreEqual("Json", FakeViewEngine.ViewContext.ViewName);
Assert.IsInstanceOfType(FakeViewEngine.ViewContext.ViewData,

                             typeof(MyViewData));
Assert.IsTrue(((MyViewData)FakeViewEngine.ViewContext

                            .ViewData).isSuccessful);
Assert.IsNotNull(((MyViewData)FakeViewEngine

                            .ViewContext.ViewData).Id);

using (MyDataContext dc = new MyDataContext())
{
var query =
dc.Messages.Where(
m => m.MessageId ==
((MyViewData)FakeViewEngine

                       .ViewContext.ViewData).Id);
//verify it was added to the database
        Assert.AreEqual(1, query.Count());

//delete it
        dc.Messages.DeleteOnSubmit(query.First());
dc.SubmitChanges();

//verify it was delete
        Assert.AreEqual(0, query.Count());
}
}

Note that in the verification block, I verify:

  1. The view being rendered
  2. The returned type of the ViewData
  3. Properties on the ViewData

Then I clean up the created message by deleting it from the database.

Important:

You must add your connection strings and membership definition in an app.config file in your test project. If you don’t then the default consrtuctor of your DataContext will fail to run because it looks for the connection string in the config file.

I am still wrapping my head around the concept of mocking, so any tips or advice will be appreciated.

Here are some good resources that I found during my struggle to get this to work.

ASP.NET MVC Resources

  1. ASP.NET MVC Framework – Part 2: Testing
  2. ASP.NET MVC Session at Mix08, TDD and MvcMockHelpers

LINQ to SQL Resources

  1. Being Ignorant with LINQ to SQL

Testing and Mocking Resources

  1. Moq: Linq, Lambdas and Predicates applied to Mock Objects
  2. Moq
  3. Rhino Mocks
  4. TDD: Test-Driven Development with Visual Studio 2008 Unit Tests