一切都取决于您的应用程序的大小。但是对于大型应用程序,您通常不会在控制器中实例化任何依赖项。它使您的代码与某些特定的数据访问提供程序实现紧密耦合。如果你明天搬到MongoDB怎么办?考虑一下您需要在应用程序中更改哪些地方。
当您对控制器进行单元测试时,这与数据访问提供者的模拟有关。您应该能够通过一些模拟实现来切换真实对象,该对象在您的应用程序中进行持久性。如果你要让你的控制器依赖于上下文并且你要在控制器中实例化上下文,那将是不可能的(或者至少非常困难)。
传统方法如下:
- 创建数据访问抽象,您的控制器将依赖它。通常存储库就是这样的抽象。
- 并使用一些依赖注入框架将此抽象的实现注入控制器。
因此,您的控制器将只知道抽象,很容易更改数据访问提供者(只需为 MongoDB 创建存储库并将该实现提供给控制器),当您进行单元测试时,也很容易提供数据访问提供者的模拟实现的控制器。
样本:
public class SalesController : Controller
{
private IOrderRepository _repository; // depend on interface
// inject some implementation of dependency into controller
public SalesController(IOrderRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
var orders = _repository.FindAll();
return View(orders);
}
}
您将使用具体存储库实现的唯一地方是依赖注入框架的配置,更改实现非常容易:
Bind<DbContext>().To<ShopEntities>();
Bind<IOrderRepository>().To<EFOrderRepository>();
进行单元测试也很容易:
[Test]
public void ShoulReturnAllOrders()
{
List<Order> orders = CreateListOfOrders();
var mock = new Mock<IOrderRepository>();
mock.Setup(r => r.FindAll()).Returns(orders);
var controller = new SalesController(mock.Object);
var result = (ViewResult)controller.Index();
mock.VerifyAll();
Assert.That(result.Model, Is.EqualTo(orders));
}