依赖注入和模拟框架之间的区别(Ninject vs RhinoMock或Moq)

时间:2011-03-25 13:37:58

标签: c# .net dependency-injection mocking

那么Ninject&和Ninject之间的区别是什么?像RhinoMock或moq这样的模拟框架?我谷歌这个,但目前还不清楚。

2 个答案:

答案 0 :(得分:97)

对于.NET,

NinjectDependency Injection

RhinoMocksMoq都是嘲弄框架。

现在两者都没有任何关系。我真的很难理解两者,所以在这里我试着解释一下。

依赖注入:是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!!

为什么呢?问问自己为什么你首先创建了一个界面?因此,您可以应对更改。那么现在,当您需要将存储库更改为其他内容时。您必须替换new MyUserRepo()

的所有行

一个简单的方法是用户工厂方法,它是IOC的另一种形式。

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 /身份验证,这取决于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,然后我就可以将我的应用切换到在这里和那里使用假类。

真的希望这很有帮助。

答案 1 :(得分:4)

Ninject是控制工具的依赖注入/反转。您可以使用它来管理类之间的依赖关系。

经典的例子是你有类似服务或数据存储库的东西。您可以要求Ninject内核为您提供接口实例,而不是在整个应用程序中使用具体类。这意味着您可以创建多个实现接口的具体类,并在一个地方交换它们。这在测试中非常有用,但远不止于此。很多IoC容器,Ninject也不例外,也会做一些事情,比如管理实例生命周期和其他一些东西。假如你想为每个web请求使用1个存储库,或者是一个类的单个实例,那就是Ninject可以非常干净地为你处理的事情。

Moq,RhinoMocks等是模拟框架,它们为您生成假类,以断言应用程序的其他部分以正确的方式与它们交互。这些实际上只对测试有用,因为模拟对象除了报告它们的访问方式之外不提供任何功能。

您可能还想查看StructureMap - structuremap.net/structuremap - 他们有一些描述模式的好文章,还有Rob Conery在IoC上的剧集 - http://www.asp.net/mvc/videos/aspnet-mvc-storefront-part-13-dependency-injection - 以及Mocking - {{3} - 这是一个很好的手表,并且描述的远比我能做的更好。