Unit Testing with Ninject in MVC 4
Asked Answered
I

1

10

I have a solution called MvcContacts with an MVC 4 project named MvcContacts and a unit testing project named MvcContacts.Test (created automatically when I checked the "enable unit testing" box in Visual Studio.

I installed the Ninject.MVC NuGet package into MvcContacts (the MVC project).

I followed this tutorial and I have everything setup with no errors and it should work fine; however, my unit testing project MvcContacts.Test has errors like this:

'MvcContacts.Controllers.HomeController' does not contain a constructor that takes 0 arguments

This is my HomeController:

namespace MvcContacts.Controllers
{
    public class HomeController : Controller
    {
        Logging.ILogger _logger;

        public HomeController(Logging.ILogger logger)
        {
            _logger = logger;
        }

        public ActionResult Index()
        {
            ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";

            _logger.LogMessage(ViewBag.Message);

            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your app description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}

This is my HomeControllerTest:

namespace MvcContacts.Tests.Controllers
{
    [TestClass]
    public class HomeControllerTest
    {
        [TestMethod]
        public void Index()
        {
            // Arrange
            HomeController controller = new HomeController(); // error on this line

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

            // Assert
            Assert.AreEqual("Modify this template to jump-start your ASP.NET MVC application.", result.ViewBag.Message);
        }

        [TestMethod]
        public void About()
        {
            // Arrange
            HomeController controller = new HomeController(); // error on this line

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

            // Assert
            Assert.IsNotNull(result);
        }

        [TestMethod]
        public void Contact()
        {
            // Arrange
            HomeController controller = new HomeController(); // error on this line

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

            // Assert
            Assert.IsNotNull(result);
        }
    }
}

How can I make my unit testing project work with Ninject?

Interior answered 13/9, 2013 at 17:35 Comment(0)
P
10

You need to pass an instance of Logging.ILogger to your constructor in your unit test. You can either new up an instance of some type that implements Logging.ILogger, or you could use a library like Moq to create a mock instance:

var mockLogger = new Moq.Mock<Logging.ILogger>();
var controller = new HomeController(mockLogger.Object);

Alternatively, you could add a default constructor to your HomeController:

public HomeController() { _logger = new /* create logger */; }

Edit

If you want to use your Ninject Kernel in your testing, you can do that, but I think it would be overkill for this simple case.

var module = new /* your module, or a test module which configures mocks */;
var kernel = new StandardKernel(module);
var controller = kernel.Get<HomeController>();

You can also use the MockingKernel extension for Ninject if you want some really magical injection, but that is almost certainly overkill for this situation.

Py answered 13/9, 2013 at 18:36 Comment(3)
Thanks I will try this but if I have to manually resolve the dependency then what good is Ninject? I thought one of the main benefits of Ninject was that it helps in unit testing.Interior
@user1477388, using Inversion of Control/Dependency Injection patterns makes it easier to unit test, but if your unit test are so complex that you need to use your IoC container (Ninject) to set up the dependencies then your unit tests may be TOO complex. The ideal unit test only uses one "real" instance (e.g., HomeController) with all other dependencies provided as mocks.Py
@SteveRuble: Unless you have layers of dependencies. If I need to mock class A to inject into class B, which is then injected into class C, you still have to test class C somehow, which means resolving the dependencies manually or using something like Ninject. Of course, everything but C would be a mock, but you still need to inject those mocks.Acuff

© 2022 - 2024 — McMap. All rights reserved.