我有一个将 NHibernate 用于 ORM 的 MVC 应用程序。每个控制器都采用一个 ISession 构造参数,然后使用该参数对域模型对象执行 CRUD 操作。例如,
public class HomeController : Controller
{
public HomeController(ISession session)
{
_session = session;
}
public ViewResult Index(DateTime minDate, DateTime maxDate)
{
var surveys = _session.CreateCriteria<Survey>()
.Add( Expression.Like("Name", "Sm%") )
.Add( Expression.Between("EntryDate", minDate, maxDate) )
.AddOrder( Order.Desc("EntryDate") )
.SetMaxResults(10)
.List<Survey>();
// other logic that I want to unit test that does operations on the surveys variable
return View(someObject);
}
private ISession _session;
}
我想通过使用 Moq 或 RhinoMocks 模拟 ISession 对象来单独对该控制器进行单元测试,而无需实际访问数据库。但是,在单元测试中模拟 ISession 接口将非常困难,因为它是通过一个流畅的接口使用的,该接口将许多调用链接在一起。
一种替代方法是通过存储库模式包装 ISession 使用。我可以写一个像这样的包装类:
public interface IRepository
{
List<Survey> SearchSurveyByDate(DateTime minDate, DateTime maxDate);
}
public class SurveyRepository : IRepository
{
public SurveyRepository(ISession session)
{
_session = session;
}
public List<Survey> SearchSurveyByDate(DateTime minDate, DateTime maxDate)
{
return _session.CreateCriteria<Survey>()
.Add( Expression.Like("Name", "Sm%") )
.Add( Expression.Between("EntryDate", minDate, maxDate) )
.AddOrder( Order.Desc("EntryDate") )
.SetMaxResults(10)
.List<Survey>();
}
private ISession _session;
}
然后我可以重写我的控制器以采用 IRepository 构造函数参数,而不是 ISession 参数:
public class HomeController : Controller
{
public HomeController(IRepository repository)
{
_repository = repository;
}
public ViewResult Index(DateTime minDate, DateTime maxDate)
{
var surveys = _repository.SearchSurveyByDate(minDate, maxDate);
// other logic that I want to unit test that does operations on the surveys variable
return View(someObject);
}
private IRepository _repository;
}
第二种方法更容易进行单元测试,因为 IRepository 接口比 ISession 接口更容易模拟,因为它只是一个方法调用。但是,我真的不想走这条路,因为:
1)创建一个全新的抽象层和更多的复杂性只是为了使单元测试更容易,这似乎是一个非常糟糕的主意,并且
2) 有很多评论反对在 nHibernate 中使用存储库模式的想法,因为 ISession 接口已经是一个类似于存储库的接口。(特别是在这里和这里查看 Ayende 的帖子)我倾向于同意这个评论。
所以我的问题是,有什么方法可以通过模拟 ISession 对象来对我的初始实现进行单元测试?如果不是,我唯一的办法是使用存储库模式包装 ISession 查询,还是有其他方法可以解决这个问题?