Как решить проблему внедрения зависимостей базового контроллера в целях тестирования? - PullRequest
6 голосов
/ 18 сентября 2009

Я реализовал свой базовый контроллер mvc под названием DefaultController, используя шаблон внедрения зависимостей, чтобы иметь возможность создавать тестовые случаи. Пример ниже:

public class DefaultController : Controller
{
    protected readonly ISessionHelper _sessionHelper;
    string _thisUserOpenID;
    protected IUsersRepository _UserRepository;
 ... 
    public DefaultController()
    { } //not for testing

    public DefaultController(ISessionHelper session, IUserRepository repo)
    {
       _sessionHelper=session;
       _UserRepository = repo;
     }
 }

Тогда мои контроллеры используют этот контроллер, homecontroller, usercontroller и т. Д.

Теперь, создавая несколько тестов, я оказался в ситуации, когда не знаю, как на самом деле использовать шаблон зависимости внедрения.

    [TestMethod]
    public void Welcome_Message_In_ViewData_Has_Coockie_User_Display_Name()
    {
        // Below I want to insert FakeRepositories using 
        //ISessionHelper and so on. but the constructor 
        //for homecontroller don't have it.
        HomeController controller = new HomeController(); 

Есть идеи?

Ответы [ 2 ]

5 голосов
/ 18 сентября 2009

Ваш HomeController должен иметь соответствующий «инъецируемый» конструктор, который затем будет вызывать базовый конструктор.

public HomeController(ISessionHelper session, IUserRepository repo)
  : base(session, repo)
    {

    }

Теперь в своем тесте вы должны создать свой HomeController, используя этот конструктор, и передать имитированный сеанс и пользовательский репозиторий. Говоря о насмешках, вас также могут заинтересовать классы Скотта Хансельмана MvcMockHelpers с кодом для многих популярных платформ для имитации.

3 голосов
/ 18 сентября 2009

Не понимаю, почему у вас два конструктора. У вас должен быть только один, избавьтесь от конструктора без параметров. Используя DI-фреймворк, такой как Castle Windsor или мой любимый, Autofac справится со всем этим для вас. Затем, что касается тестирования, используйте что-то вроде Moq. Т.е.

public DefaultController(ISessionHelper session, IUserRepository repo)
{
   _sessionHelper = session;
   _UserRepository = repo;
}

Зарегистрируйте DefaultController, ISessionHelper и IUserRepository в своей инфраструктуре DI. Что-то вроде:

Register(new DefaultController()); (it is something like that in Autofac)
Register<SessionHelper>().As<ISessionHelper>();
Register<UserRepository>().As<IUserRepository>();

Таким образом, вы можете извлечь DefaultController из контейнера, и структура DI введет эти два параметра за вас. Я обернул статический метод для доступа к моему контейнеру DI, он выглядит так:

var controller = IoC.Resolve<DefaultController>();

В основном отправляйтесь в Autofac и посмотрите. Также есть веб-модуль для регистрации ваших контроллеров.

Тогда для тестирования просто используйте Moq или найдите какую-нибудь форму "AutoMocker" (Google it). Я бы сделал:

var session = new Mock<ISessionHelper>();
var repo = new Mock<IUserRepository>();
repo.Setup(s => s.FindById(123)).Returns(new User());

var conroller = new DefaultController(session.Object, repo.Object);
controller.Execute();

Также есть репозитории. С .Net, дженериками и т.д ... просто создайте себе хорошую ISession.

var session = IoC.Resolve<ISession>();
var user1 = session.Get<User>(123);
var user2 = session.Get<User>(u => u.Username == "admin");
session.Update(user3);

Означает, что вам нужно передать только одно, и вы можете использовать его для чего угодно. Вместо того, чтобы проходить иногда во многих хранилищах. Также хорошо настраивает вас на паттерн Unit of Work.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...