Являются ли классы модульного тестирования в веб-проекте ASP.NET MVC хорошим примером? - PullRequest
6 голосов
/ 23 января 2011

Я учусь TDD. Я знаю о внедрении зависимостей, когда вы помещаете зависимости класса в параметры конструктора и передаете их, передавая реализации по умолчанию из конструктора по умолчанию, например;

public AccountController() : this( RepositoryFactory.Users())
{
}

public AccountController( IUserRepository oUserRepository)
{
 m_oUserRepository = oUserRepository;
}

RepositoryFactory - простой статический класс, который возвращает выбранные реализации для текущей сборки

Но проект веб-приложения ASP.NET MVC по умолчанию этого не делает, вместо этого DI принимает форму открытых свойств, которые назначаются в инициализаторе объекта в тестовом классе, например; from AccountController.cs:

protected override void Initialize(RequestContext requestContext)
{
 if (FormsService == null)
  { FormsService = new FormsAuthenticationService(); }
 if (MembershipService == null)
  { MembershipService = new AccountMembershipService(); }

 base.Initialize(requestContext);
}

А в тестовом классе AccountControllerTest.cs:

private static AccountController GetAccountController()
{
 AccountController controller = new AccountController()
 {
  FormsService = new MockFormsAuthenticationService(),
  MembershipService = new MockMembershipService(),
  Url = new UrlHelper(requestContext),
 };
 //snip
}

Итак, теперь мой класс AccountController имеет два подхода к внедрению зависимостей. Какой из них я должен использовать? Конструктор инъекций или общедоступные свойства?

Думаю, конструктор инъекций ...

Является ли использование ASP.NET MVC общедоступных свойств подобным образом, потому что вам нужно предоставить конкретный способ внедрения в конструктор, а базовое веб-приложение «Создать новое» должно быть общим в качестве отправной точки?

Ответы [ 2 ]

11 голосов
/ 23 января 2011

Примеры в ASP.NET MVC являются отличной демонстрацией того, как не использовать DI .

Прежде всего, использование конструктора по умолчанию, а также перегруженного конструктора вводит неоднозначность : класс управляет своими собственными зависимостями или получает их извне? По-видимому, это не может действительно решить.

Во-вторых, реализация по умолчанию вводит тесную связь , потому что вы не можете создать новый экземпляр реализации по умолчанию без ссылки на него. Однако весь смысл DI заключается в том, чтобы обеспечить слабую связь .

К сожалению, мы часто видим эту идиому. В моей книге я называю это анти-паттерн «Инъекция ублюдка» ; Я взял имя из одного из 1010 * Oren Eini / Ayende Rahien многих посторонних постов в блоге, где он просматривает очень похожий пример .

В качестве общего совета я рекомендую использовать Constructor Injection в подавляющем большинстве случаев. Его легко реализовать и он имеет очень сильную семантику: он заставляет потребителя предоставлять экземпляр зависимости, фактически заявляя, что зависимость является обязательной.

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

1 голос
/ 23 января 2011

Взгляните на структурную карту . Вы правы ... внедрение в конструктор является предпочтительным методом DI / IoC. Прочтите эту статью Мартина Фаулера . Надеюсь, это поможет вам.

...