MVC 3 + Ninject + Moq + Unit Test Step By Step
In the following example, I'll show you how to use Ninject on a simple ASP.Net MVC applicatoin, and I'll write a Unit Test for the Home Controller with Moq.
The MVC Applicatoin
Lets start with a plain MVC 3 applicaiton
Start Visual Studio 2010 and then create a new project, select ASP.NET MVC 3 Web Application.
In the Name and Solution Name text box, enter "SimpleNinjectDemo" then press OK.
Next, select "Internet Application", View Engine should be Razor, remember to check "Create a unit test project". Click OK to continue.
At this point, the newly created project should have file structure look like below picture
Now add a "Services" folder to SimpleNinjectDemo project, like below
Inside the Services folder, let us add an interface for messaging called IMessagingService. We will be using the messaging service in our home controller that will be creating in the next couple of steps.
Add an interface called IMessagingService.cs under Services folder
namespace SimpleNinjectDemo.Services
{
public interface IMessagingService
{
string HelloWorld();
}
}
Now let's create the actual messaging service that is about to hook up to the previous IMessagingService interface. Add a class called MessagingService.cs under Services folder
namespace SimpleNinjectDemo.Services
{
public class MessagingService : IMessagingService
{
public string HelloWorld()
{
return "Hello World";
}
}
}
At this point, the project folder should look like this
With the Messaging Service in place, we can now start working on the controller to consume the service
Let's modify the HomeController as below
using System.Web.Mvc;
using SimpleNinjectDemo.Services;
namespace NinjectSimpleDemo.Controllers
{
public class HomeController : Controller
{
private IMessagingService MessagingService { get; set; }
public HomeController(IMessagingService messagingService)
{
this.MessagingService = messagingService;
}
public ActionResult Index()
{
ViewBag.Message = MessagingService.HelloWorld();
return View();
}
public ActionResult About()
{
return View();
}
}
}
Ninject comes to rescue
As you can see, we added a constructor which has a parameter implementing IMessagingService. This technique is called Dependency Injection.
Ok, enough talk, let's compile and run the application to see what's the effect.
Oops, the newly introduced HomeController constructor needs a MessagingService object as parameter, what should I do to create and pass it into HomeController?
... It's easy, here comes Ninject, it can help to solve the above problem in few lines of code.
Let's install Ninject.MVC3 using NuGet package installer.
After Ninject.MVC3 installed, you'll notice the project will have a new folder App_Start and a file NinjectMVC3.cs or NinjectWebCommon.cs both are same under it
OR
This file acts as the setup file for Ninject, it takes care of all bindings and start up. Now let's modify NinjectMVC3.cs to hook up the HomeController's constructor with the MessagingService.
Add below line to RegisterServices function.
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMessagingService>().To<MessagingService>();
}
Run the project again.
Isn't it so simple, our Hello World project now utilize Ninject to inject the MessingingService dependency to a Controller.
Unit Test
Let's get back to our Test project for demo Moq and Unit Test. Because we will use Moq to setup mock to MessagingSerive, let's install it using NuGet Package Installer.
Right click simpleNinjectDemo.Tests Project and add Moq.
see the Reference folder there is Moq dll added
Now open HomeControllerTest.cs in SimpleNinjectDemo.Test project, and then remove the whole About() test, or just comment it out, we will only focus on Index() test.
HomeControllerTest.cs should look like this
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NinjectSimpleDemo.Controllers;
namespace SimpleNinjectDemo.Tests.Controllers
{
[TestClass]
public class HomeControllerTest
{
[TestMethod]
public void Index()
{
// Arrange
HomeController controller = new HomeController();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.AreEqual("Welcome to ASP.NET MVC!", result.ViewBag.Message);
}
}
}
If you build the test project now, the compiler will return error message"'NinjectSimpleDemo.Controllers.HomeController' does not contain a constructor that takes 0 arguments" . It's time to call Moq for help.
The HomeController now requires an object as a parameter and we will mock one for it.
Add below code to the Arrange section
// Arrange
var expectedResult = "Hello, Unit Test!";
var messagingService = new Mock<IMessagingService>();
messagingService.Setup(m => m.HelloWorld()).Returns(expectedResult);
And then put messagingService.Object as the parameter of HomeController constructor
HomeController controller = new HomeController(messagingService.Object);
Lastly, modify the Assert part like below
// Assert
Assert.AreEqual(expectedResult, result.ViewBag.Message);
Run the Test by right click the class and then choose Run Tests
Very good, the test passed successfully.
This is a simple demo that combine the use of ASP.Net MVC 3, Ninject, Moq and Unit Test, for more information of each tools, please refer to their own website.
Sumit Kesarwani
21-Nov-2013