我一直在研究使用EF实现存储库模式的各种方法,特别是使用通用存储库。
我一直在尝试使用具有IContext属性的IRepository,因此IRepository的任何实现之间的唯一区别就是上下文。我发现这很困难,我已经放弃了“伪上下文”的方法,现在只需要一个List的字典作为虚假存储库中的“上下文”:
public Dictionary<Type, object> _sets = new Dictionary<Type, object>();
要操纵它,会在假货中做这样的事情:
public void Add<T>(T entity) where T : class
{
var set = _sets[typeof (T)] as IQueryable<T>;
var updatedSet = set.ToList();
updatedSet.Add(entity);
_sets[typeof (T)] = updatedSet.AsQueryable<T>();
}
在真实存储库中,我可以使用:
void Add<T>(T entity)
{
Set<T>().Add(entity);
}
在我的Update方法中,我必须有类似的不同实现来容纳继承DbContext的真实上下文,并使用基于集合的方法来伪造。
这种方法让我感到紧张。正如其他人在其他问题中提到的那样,现在我的存储库实现是如此不同,以至于我觉得我可以相信测试,直到它与假的和真实的存储库一起运行。
我只是一个正在过度思考的菜鸟吗?或者是否有更好的方法来实现更像DbContext的虚假上下文,因此我不必拥有实现存储库接口的完全不同的类?
总结一下:我理解使用内存存储库进行测试的优势。我的问题是,当我必须制作两个不同的存储库实现时,这是否意味着我做错了,或者这只是假装测试的成本,如果逻辑测试通过,我不应该'这么多汗水?
答案 0 :(得分:0)
这是我们正在处理的项目中所做的:我们在EF周围有一个存储库包装器类,这样我们就可以在需要时在单元测试中使用模拟器。我考虑过像你一样在内存库中做一个,但我最终决定反对它,因为我只需要它来进行查询。但是,由于Linq To Entities是Linq to Objects的子集。单元测试可能会通过,但随后集成测试失败,因为您可能使用的功能不是Linq to Entities的一部分。如果我需要对该查询进行集成测试并且不能信任单元测试,那么这两种方法都没有意义。
对于单元测试,我只是模拟了存储库并验证了调用了适当的方法(Insert或其他)。对于删除/插入/不管的集成测试,只需点击实际的数据库即可。
对于实际的查询,我只进行了集成测试。我将查询移动到一个单独的函数。我的代码将调用该函数来检索查询结果,我可以单独集成测试函数与其中的查询,并单元测试查询结果的处理。
我不知道这是否有意义,或者是否有更好的方法,但这就是我最终做的事情。
或者,如果您想继续使用内存中实现 我认为你应该能够做到以下几点:
只需拥有一个对象列表,并使用OfType返回正确的类型:
public TEntity Get<TEntity>(System.Linq.Expressions.Expression<Func<TEntity, bool>> where, params System.Linq.Expressions.Expression<Func<TEntity, object>>[] includeProperties) where TEntity : class
{
return _repositories.OfType<TEntity>().AsQueryable().Where(where).FirstOrDefault();
}
public TEntity Insert<TEntity>(TEntity tEntity) where TEntity : class
{
_repositories.Add(tEntity);
return tEntity;
}