Ninject http://ninject.org/ is 依赖注入 http://en.wikipedia.org/wiki/Dependency_injection对于.NET。
犀牛模型 http://www.ayende.com/projects/rhino-mocks.aspx and Moq http://code.google.com/p/moq/都是模拟框架。
现在两人已经没有任何关系了。我真的很难理解两者,所以我在这里尝试解释一下。
依赖注入:是控制反转的一种实现(我们称之为控制反转)。你不要混淆两者。您正在控制从代码中创建对象。依赖关系,比如IRepository
不会由您的类/代码创建,而是由injected由其他人开发的依赖注入框架。
假设你有
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()
.
一种简单的方法是使用工厂方法,它是 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";
}
}
所以现在,当你通过这个fake回购。如果您的测试失败,您知道这是其他原因,而不是数据库。
我的例子很简单,但是如果它有大量的接口。你需要写很多fake代码,代码很多,臃肿!
所以你可以使用模拟框架在这里编写更少的代码。
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 http://mef.codeplex.com/(内置于.Net4)用于依赖注入。然后我就很少了#Ifdef
关于哪些类的声明Export
(或暴露)基于#define
象征。所以我只换一个#define
我可以将我的应用程序切换为到处使用假类。
真的希望这有帮助。