2010-02-17 82 views
2

我想要一个很好的方式来清理我的控制器,使他们更可测试,而不必依赖于一个常量的数据库连接。我认为我有一个体面的开始,用IObjectContext抽象出我的对象上下文。这适用于上下文,但我的下一个问题是我有一个generic repository,我在整个项目中使用了许多操作方法(请参阅下面的代码)。干净的方式来测试ASP.NET MVC控制器不击中数据库?

除了默认构造函数外,我的控制器还包含一个接受IObjectContext(简单依赖注入)的重载。在我的单元测试中,我可以轻松地模拟IObjectContext。我的问题是在各种操作方法中处理我的通用存储库。我可以向控制器添加一些额外的构造函数重载,但是恐怕这会很麻烦,很快。然而,由于没有这样做,我根本无法想到一种干净的方法来提高可测试性,因此我不必依靠数据库连接。

有没有简单的解决方案,我忽略了?

/// <summary> 
/// Initializes a new instance of the HomeController class 
/// </summary> 
public HomeController(IObjectContext context) 
{ 
    _context = context; 
} 

/// <summary> 
/// GET: /home/index 
/// </summary> 
/// <returns>Renders the home page</returns> 
public ActionResult Index() 
{ 
    List contacts; 
    HomeViewModel model; 

    using (IRepository<Contact> repository = new DataRepository<Contact>(_context)) 
    { 
     contacts = new List(repository.GetAll()); 
    } 

    model = new HomeViewModel(contacts); 

    return View(model); 
}

如果我必须去增加额外的构造函数重载,以适应我的顾虑的途径,我正在考虑加入一些私人性质的(直到需要时它会deffer存储库的实例化),以我的控制器,用于动作方法使用的每个存储库。例如:

private IRepository<Contact> _contactRepository; 

private IRepository<Contact> ContactRepository 
{ 
    get 
    { 
     return _contactRepository ?? (_contactRepository = new DataRepository<Contact>()); 
    } 
}

对于单元测试目的,我可以使用构造函数重载预先初始化存储库。

你对此有何看法?我是否错过了一些应该明显的清洁剂?

+0

你可以嘲笑你的存储库吗? – Pace 2010-02-17 13:25:50

+0

谢谢你的回应。这实际上是我的观点。我当然可以,但是有没有一种干净的方式来实现我的控制器,这样我就不会为每个使用另一个存储库的可能操作方法重载构造函数。例如,一种行为方法依赖于几个不同的存储库。 – senfo 2010-02-17 13:33:47

回答

5

首先,摆脱你目前的混蛋注射构造函数重载。使用DI,你只需要一个构造函数,这就是所有依赖关系的构造函数。 (要启用ASP.NET MVC运行时创建控制器,请实现自定义IControllerFactory。)

下一步是通过构造函数注入所有依赖关系。当你认为它变得混乱,因为有太多的构造函数参数,这是一个好兆头,你违反了Single Responsibility Principle。当发生这种情况时,你提取Aggregate Service

冲洗和重复:)

1

那么,我做你最后的例子显示所有的时间注入我的控制器嘲笑。它确实有一点嗅觉(为可测试性设计),但它不是坏的编码,对测试非常有用。

1

您使用一个通用存储库是一个多依赖注入的依赖,隐形装置。您应该能够看到特定Controller使用的所有依赖关系:通用存储库将您隐藏在控制器内部深处的这一事实,这使维护(和单元测试)代码变得更加困难。我的建议是:使用具体的存储库。

你也可以看看domain-driven design stuff

相关问题