且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-11-03 19:21:58

Ninject 是.NET的依赖注入



RhinoMocks Moq 都是嘲弄的框架。



现在两者与彼此无关。我真的很难理解,所以这里我去试图解释。



依赖注入:是一个实现(让它调用它)控制。你不要混淆这两个。您正在控制从代码中创建一个对象。依赖关系,就像说一个 IRepository 不会被你的类/代码创建,而是由其他人注入的注入框架。



让我们说你有

 界面IUserRepository 
{
string GetUserName(int id); //简单的一个方法
}

现在你有一个实际的实现:

  class MyUserRepo:IUserRepository 
{
string GetUserName(int id)
{
//在此处从您的数据库中获取您的用户名。
}
}

现在,在这个地方,你会有:

  IUserRepository repo = new MyUserRepo(); //这是坏的! 

为什么?问问自己为什么你首先做了一个界面?所以你可以应付变更。那么现在,当你需要把你的仓库改成别的地方。您必须更换所有具有的新行MyUserRepo()



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

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

并使用它:

  IUserRepository rep = RepoFactory.UserRepo; 

现在,当您需要更改存储库时,您只需要更改您的工厂。通过执行所有工作,依赖关系注入将其提升到一个新的水平。您不需要更改代码(或可能是几个声明)。

  IUserRepository repo; 
//这个神奇地得到一个基于某个配置的正确的实例。






一个模拟框架男孩这就像火箭科学给我。但是史蒂文·桑德森斯(Steven Sandersons)的书有一个很好的简单解释。



我们继续使用 IUserRepository



现在,您必须测试一些复杂的UI /验证,这取决于 IUserRepository

  class UserDisplay:UserControl 
{
UserDisplay(IUserRepository repo)
{//显示用户名或这里的东西..
}
}

,当您使 MyUserRepo 的实例 IUserRepository 时。如果出现问题,你不知道出了什么问题!是您的用户控制还是数据库连接?



您希望让测试更具有决定性,就像有人说的那样。



所以你做一个假的用户信息库。

  class FakeUserRepo: IUserRepository 
{
public string GetUserName(int id)
{
returnFakeUser;
}
}

所以现在,当你传递这个回购。如果你测试失败,你知道它是别的,而不是数据库。



我的例子很简单,但是如果它有大量的接口。你需要编写大量的假的代码,它的代码很多!



所以你可以使用一个嘲笑的框架来编写更少的代码。



Moq使用流畅的界面,相当不错。使用Moq将如下所示:

  var fakeUserRepo = new Mock< IUserRepository>(); 
fakeUserRepo.Setup(f => f.GetUserName(It.IsAny< int>))。Returns(FakeUser);
//与类声明相同的事情
fakeUserRepo.Object; //返回类型为IUserRepository的伪造对象

创建假对象变得很容易=)



现在我希望你看到如何使用这两个方面有利于您。您可以使用嘲笑的框架创建假冒的对象,然后使用依赖注入在正确的时间连接正确的对象。



对于我较小的Silverlight应用程序,我使用 MEF (内置于.Net4)。然后在导出(或公开)的类的声明上,我有一点 #Ifdef 基于 #define 符号。所以我只是更改一个 #define ,我可以将我的应用程序切换到这里使用假类。



真的希望这是有帮助的。


So what is the difference between Ninject & a mocking framework like RhinoMock or moq? I google'd this but it is still unclear.

Ninject is Dependency Injection for .NET.

RhinoMocks and Moq are both mocking frameworks.

Now both have nothing to do with each other. I really had trouble understanding both so here I go trying to explain.

Dependency Injection: is an implementation (lets call it) of Inversion of Control. You don't confuse the two. You are taking the control of creating an object out of your code. Dependencies, like say a IRepository would not be created by your classes/code but instead injected by someone else, a dependency injection framework.

Lets say you have

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

Now you have an actual implementation:

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

Now all over the place, you'll have:

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

Why? Ask yourself why you made an interface in the first place? So you can cope with change. Well now, when you need to change your repository to something else. You have to replace all the lines that have new MyUserRepo().

A simple method is user a factory method which is another form of IOC.

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

And use it like this:

IUserRepository rep = RepoFactory.UserRepo;

Now when you have to change your repository you have to change only your factory. Dependency injection takes this to the next level by doing all the work. You don't need to change the code at all (or maybe a few declarations).

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


A Mocking Framework : Boy this was like rocket science to me. But Steven Sandersons book had a brilliant simple explanation.

We keep going on with the IUserRepository.

Now you have to test some complicated UI/Authentication whatever that depends on IUserRepository.

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

Now in your test, when you make IUserRepository an instance of MyUserRepo. If something goes wrong you don't know what went wrong! Was it your user control or your database connection?

You want make the test more deterministic as someone said.

So you make a fake user repository.

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

So now, when you pass this fake repo. If you're test fails you KNOW it was something else, not the data base.

My example was simple, but if its a large number of Interfaces. You'll need to write a lot of fake code, its a lot of code bloat!

So you can use a mocking framework to write less code here.

Moq uses a fluent interface and is quite nice. Using Moq would look like this:

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

Creating fake objects becomes a lot easier =)

Now I hope your seeing how you can use both to your advantage. You can create your fake objects with a mocking framework, then use dependency injection to hook up the right objects at the right time.

For my smaller Silverlight applications I use MEF (Inbuilt in .Net4) for Dependency Injection. And then I have little #Ifdef on the declarations for which classes to Export (or expose) Based on a #define symbol. So I just change one #define and I can switch my app to using fake classes here and there.

Really Hope that was helpful.