我正在开发一个 MVC 项目的新阶段。第一阶段相当小,也不是很复杂。下一阶段将非常复杂且规模更大。在第一阶段,我们讨论了然后出于各种原因放弃了进行彻底自动化测试的想法。
在新阶段,我希望我们的团队投资于自动化测试。我认为如果没有依赖注入,我们将无法做任何有用的事情,因为我们希望将数据库工作存根以使我们的测试可控。
我正在努力将依赖注入改造到我的业务层中。我们现有的业务对象具有状态、行为,并负责加载自身的实例(通过静态方法)。例如,我们可能有这个过于简化的例子:
public class User
{
public User(string userName)
{}
public bool Authenticate()
{}
public static User GetByUserName(string userName)
{
//Do some DB querying, and then map the data object to a new instance:
UserRepository repository = new UserRepository();
var databaseObject = repository.list(u => u.userName = userName);
User user = new User();
user.userName = databaseObject.userName;
// populate other fields
return user;
}
}
乍一看,我似乎需要:
- 在构造函数中注入存储库作为依赖项
- 将 GetByUserName 更改为不再是 User 中的静态方法
- 做某种工厂以便能够在 GetByUserName 方法中创建 User 的实例
我无法弄清楚如何以合理的方式完成所有这些。#1 是微不足道的,但 #2 和 #3 不那么微不足道。这是我正在考虑如何做#2:
- 基本上保持结构不变,只需删除 static 关键字。这意味着为了通过用户名获取用户,您必须创建用户对象的实例,然后调用 GetByUserName 方法。这没有通过我高度复杂的气味测试。
- 将加载和保存用户的责任转移到某种 UserCollection 对象。这对我来说似乎很可疑,因为这意味着几乎每个业务对象都需要一个底层集合对象,并且因为它会使我的域模型更加贫乏。
- 直接与存储库交互。现在控制器可能会调用 User.GetByUserName() 来获取用户域对象来做一些工作。相反,控制器会知道存储库并调用 Repository.list()。这对我来说似乎是泄漏的——突然控制器感觉它在做生意。
然后是#3。看起来我的选择是要么使用我的 IOC 容器来注入工厂方法(例如 autofac 工厂委托),要么为每个对象手动创建工厂。使用 autofac 方法似乎有漏洞,因为我必须在我的单元测试中使用 autofac 或者为每个对象存根一个工厂委托。为所有对象创建工厂似乎很麻烦,因为在某些时候,我给开发人员施加了很大的工作量,只是为了能够在不知道我的 IOC 容器的情况下使用 DI。
我已经尽我所能搜索这些主题,但我真的没有看到很多不涉及上述缺点的具体例子。
有哪些技巧可以解决 #2 和 #3 而不会失去“好的设计”或“做太多的工作”?