【问题标题】:Are the unit test classes in ASP.NET MVC web project a good example?ASP.NET MVC Web 项目中的单元测试类是一个很好的例子吗?
【发布时间】:2011-06-13 21:16:48
【问题描述】:

我正在学习 TDD。我知道依赖注入,您可以将类的依赖项放在构造函数的参数中并传入它们,从默认构造函数传入默认实现,例如;

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

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

RepositoryFactory 是一个简单的静态类,它返回为当前构建选择的实现

但默认的 ASP.NET MVC Web 应用程序项目并没有这样做,而是 DI 采用公共属性的形式,这些属性在测试类的对象初始化程序中分配,例如;来自 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 使用公共属性是不是因为你需要提供一种特定的方式来注入构造函数,而基本的“新建”Web 应用程序需要通用作为起点?

【问题讨论】:

    标签: c# asp.net-mvc dependency-injection tdd


    【解决方案1】:

    ASP.NET MVC 中的示例很好地演示了如何使用 DI

    首先,使用默认构造函数和重载构造函数会引入歧义:类是控制自己的依赖关系,还是从外部获取它们?显然,它不能真正决定。

    其次,拥有默认实现会引入紧密耦合,因为您无法在没有引用的情况下创建默认实现的新实例。但是,whole point of DI is to enable loose coupling.

    不幸的是,我们经常看到这个成语。在my book 我称之为Bastard Injection 反模式;我从Oren Eini/Ayende Rahien 的许多固执己见的博客文章中的一篇中取名,其中he walks through a very similar example

    作为一般建议,我建议在绝大多数情况下使用构造函数注入。它易于实现并且具有很强的语义:它强制消费者提供依赖的实例,有效地表明依赖是强制性的。

    另一方面,

    Property Injection 意味着依赖项是可选的,因为编译器不会强制您分配值。在大多数情况下,依赖关系并不是真正可选的,因此应该很少使用这种模式。

    【讨论】:

    • 谢谢马克,现在明白了。是模棱两可还是方便?对于控制器,我只看到两种用途(可能在我的无知中);编译的应用程序和测试项目。编译后的应用程序仅使用默认构造函数中的默认实现。这会比使用 IOC 容器更快,不是吗?
    • 嗯,我想我明白了。我正在阅读有关依赖项具有依赖项的嵌套 IOC。使用 IOC,这可以通过 IoC.Resolve(); 之类的一行来解决
    • 马克,你能帮我更好地理解为什么不使用“混蛋注射”吗?正如我所看到的,该类仍然允许松散耦合,因为您不必使用默认构造函数。诚然,代码对 RepositoryFactory 有静态依赖,但您不必使用它。此外,“歧义”是一项功能:使用默认依赖项或注入您自己的依赖项。这有什么问题?
    • Bastard Injection 的问题在于它创建了与默认依赖项的紧密耦合。如果调用者调用默认构造函数,它还允许调用者过早地组成对象图。在我的书第 5 章中有更详细的解释:affiliate.manning.com/idevaffiliate.php?id=1150_236
    • 嗯,这些似乎都是次要的问题。我会进一步阅读。
    【解决方案2】:

    看看structuremap。你是对的......构造函数注入是 DI/IoC 的首选方法。看看这个article by Martin Fowler。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-27
      • 2015-10-30
      • 1970-01-01
      • 2016-06-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多