Разница между внедрением зависимостей и Mocking (Ninject против RhinoMock или Moq) - PullRequest
38 голосов
/ 25 марта 2011

Так в чем же разница между Ninject и фреймворком вроде RhinoMock или moq? Я google'd это, но это все еще неясно.

Ответы [ 2 ]

97 голосов
/ 25 марта 2011

Ninject is Внедрение зависимостей для .NET.

RhinoMocks и Moq являются насмешливыми структурами.

Теперь оба не имеют ничего общего друг с другом. У меня действительно были проблемы с пониманием того и другого, поэтому здесь я пытаюсь объяснить.

Внедрение зависимостей : это реализация (давайте назовем это) Inversion of Control. Вы не путаете их. Вы берете на себя управление созданием объекта из своего кода. Зависимости, такие как, скажем, IRepository не будут создаваться вашим классом / кодом, а вместо этого внедряются кем-то другим, каркасом внедрения зависимостей.

Допустим, у вас есть

interface IUserRepository
{
 string GetUserName(int id);//one method for simplicity
}

Теперь у вас есть фактическая реализация:

class MyUserRepo : IUserRepository
{
 string GetUserName(int id)
 {
  //grab your username from your data base here.
 } 
}

Теперь повсюду у вас будет:

IUserRepository repo = new MyUserRepo();//this is bad!!

Почему? Спросите себя, почему вы сделали интерфейс в первую очередь? Так что вы можете справиться с change . Хорошо, теперь, когда вам нужно изменить свой репозиторий на что-то другое. Вы должны заменить все строки, которые имеют new MyUserRepo().

Простой метод - метод фабрики пользователя, который является другой формой МОК.

class RepoFactory
{
 public static IUserRepository UserRepo
 {
  get {return MyUserRepo();}
 } 
}

И используйте это так:

IUserRepository rep = RepoFactory.UserRepo;

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

IUserRepository repo; 
//this magically gets the right instance based on some config somewhere.

Дразнящая структура : Мальчик, это было для меня как ракетостроение. Но у книги Стивена Сандерсонса было блестящее простое объяснение.

Мы продолжаем с IUserRepository.

Теперь вам нужно протестировать несколько сложных UI / Authentication независимо от того, что зависит от IUserRepository.

class UserDisplay : UserControl
{
  UserDisplay(IUserRepository repo)
  {//display the username or something here..
  } 
}

Теперь в вашем тесте, когда вы делаете IUserRepository экземпляром MyUserRepo. Если что-то идет не так, вы не знаете, что пошло не так! Это был ваш пользовательский контроль или подключение к базе данных?

Вы хотите сделать тест более детерминированным, как кто-то сказал.

Итак, вы создаете фальшивый пользовательский репозиторий.

class FakeUserRepo : IUserRepository
{
  public string GetUserName(int id)
  {
    return "FakeUser";
   }
}

Итак, теперь, когда вы проходите это фальшивое репо. Если ваш тест не пройден, вы ЗНАЕТЕ, что это что-то другое, а не база данных.

Мой пример был прост, но если его большое количество интерфейсов. Вам нужно будет написать много фальшивых кодов, это очень много кода!

Таким образом, вы можете использовать фальшивый фреймворк, чтобы писать меньше кода здесь.

Moq использует свободный интерфейс и довольно хорош. Использование Moq выглядело бы так:

var fakeUserRepo = new Mock<IUserRepository>();
fakeUserRepo.Setup(f => f.GetUserName(It.IsAny<int>)).Returns("FakeUser");
//does the same thing as the class declaration
fakeUserRepo.Object;//this returns fake object of type IUserRepository

Создание поддельных объектов становится намного проще =)

Теперь я надеюсь, что вы видите, как вы можете использовать оба в своих интересах. Вы можете создавать свои поддельные объекты с помощью фиктивной инфраструктуры, а затем использовать внедрение зависимостей для подключения нужных объектов в нужное время.

Для своих небольших приложений Silverlight я использую MEF (встроенный в .Net4) для внедрения зависимостей. И тогда у меня мало #Ifdef в объявлениях, для каких классов Export (или выставлять) на основе символа #define. Поэтому я просто меняю один #define и могу переключить свое приложение на использование поддельных классов тут и там.

Действительно надеюсь, что это было полезно.

4 голосов
/ 25 марта 2011

Ninject - это инъекция зависимостей / инверсия управляющего инструмента. Вы используете это для управления зависимостями между классами.

Классический пример - если у вас есть что-то вроде сервиса или хранилища данных. Вместо того, чтобы использовать конкретный класс в приложении, вы можете попросить ядро ​​Ninject предоставить вам экземпляр интерфейса. Это означает, что вы можете создать несколько конкретных классов, реализующих интерфейс, и поменять их в одном месте. Это чрезвычайно полезно при тестировании, но выходит далеко за рамки этого. Множество IoC-контейнеров, Ninject не является исключением, также будут выполнять такие функции, как управление жизненными циклами экземпляров и множество других вещей. Скажем, если вы хотите использовать 1 репозиторий на каждый веб-запрос или один экземпляр класса, об этом Ninject может позаботиться о вас очень аккуратно.

Moq, RhinoMocks и т. Д. Являются фальшивыми фреймворками, они генерируют фальшивые классы, чтобы вы могли утверждать, что другие части приложения взаимодействуют с ними корректным образом. Они действительно полезны только для тестирования, поскольку макетированные объекты не предоставляют никаких функций, кроме сообщения о том, как к ним обращались.

Возможно, вы также захотите проверить StructureMap - structuremap.net/structuremap - у них есть несколько хороших статей, описывающих шаблон, а также Роб Конери делает эпизоды на IoC - http://www.asp.net/mvc/videos/aspnet-mvc-storefront-part-13-dependency-injection - и на Mocking - http://www.asp.net/mvc/videos/aspnet-mvc-storefront-part-12-mocking - это хорошие часы, которые лучше меня описывают, о чем каждый.

...