Модульное тестирование с Ninject в MVC 4

У меня есть решение под названием MvcContacts с проектом MVC 4 с именем MvcContacts и проектом модульного тестирования с именем MvcContacts.Test (созданный автоматически, когда я проверил поле «включить модульное тестирование» в Visual Studio.

Я установил пакет NuGet Ninject.MVC в MvcContacts (проект MVC).

Я следовал этому руководству, и у меня все настроено без ошибок, и оно должно работать отлично; однако в моем проекте модульного тестирования MvcContacts.Test есть такие ошибки:

«MvcContacts.Controllers.HomeController» не содержит конструктор, который принимает 0 аргументов

Это мой 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();
        }
    }
}

Это мой 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);
        }
    }
}

Как я могу заставить мой проект модульного тестирования работать с Ninject?


person user1477388    schedule 13.09.2013    source источник


Ответы (1)


Вам нужно передать экземпляр Logging.ILogger вашему конструктору в модульном тесте. Вы можете либо создать новый экземпляр некоторого типа, который реализует Logging.ILogger, либо использовать библиотеку, например Moq для создания фиктивного экземпляра:

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

В качестве альтернативы вы можете добавить конструктор по умолчанию в свой HomeController:

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

Изменить

Если вы хотите использовать свой Ninject Kernel в своем тестировании, вы можете это сделать, но я думаю, что это было бы излишним для этого простого случая.

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

Вы также можете использовать расширение MockingKernel для Ninject, если вам нужна действительно волшебная инъекция, но это почти наверняка является излишним для этой ситуации.

person Steve Ruble    schedule 13.09.2013
comment
Спасибо, я попробую это, но если мне придется вручную разрешить зависимость, то что хорошего в Ninject? Я думал, что одним из основных преимуществ Ninject является то, что он помогает в модульном тестировании. - person user1477388; 13.09.2013
comment
@user1477388 user1477388, использование шаблонов Inversion of Control/Dependency Injection упрощает модульное тестирование, но если ваш модульный тест настолько сложен, что вам нужно использовать контейнер IoC (Ninject) для настройки зависимостей, тогда ваши модульные тесты могут быть СЛИШКОМ сложными . В идеальном модульном тесте используется только один реальный экземпляр (например, HomeController), а все остальные зависимости представлены в виде макетов. - person Steve Ruble; 13.09.2013
comment
@SteveRuble: если у вас нет уровней зависимостей. Если мне нужно имитировать класс A для внедрения в класс B, который затем внедряется в класс C, вам все равно придется тестировать класс C каким-то образом, что означает разрешение зависимостей вручную или использование чего-то вроде Ninject. Конечно, все, кроме C, будет макетом, но вам все равно нужно внедрить эти макеты. - person Chris Pratt; 28.02.2014