如何在具有存储库模式的实体框架中伪造DbContext.Entry方法
本文关键字:框架 实体 伪造 DbContext 方法 Entry 模式 存储 | 更新日期: 2024-08-10 00:31:55
因为我想对代码进行单元测试,所以我在MVC4应用程序中实现了存储库模式。我按照这段代码制作了一个Context接口,一个假的Context,并使用了一个假的System.Data.Entity.DbSet
实现。
不幸的是,就像我面前的两张海报一样(这里和这里),我没能嘲笑DbContext.Entry method
。我使用这种方法更新代码中的数据库条目,如下所示:
DbContext.Entry(order).State = EntityState.Modified;
我还没有找到这个问题的解决方案,只有那些说这样的话的人:
"单元测试这个代码有什么意义?你伪造了Find方法,则您伪造DbEntityEntry,并且将没有真正的逻辑测验"
或
在继续之前,请阅读本文和所有相关问题。(…)如果您想测试您的存储库,请创建与真实数据库对话的集成测试。
这一切都很好,但仍然没有答案。我读了评论,我仍然想要这个Entry方法,这样我就可以在单元测试中使用假上下文和模拟对象。当然,我也会使用集成测试,但它们不如一些快速的单元测试快。
当我尝试一些实现时,我收到的错误是Error 2 'Project.Models.Order' does not contain a definition for 'State' and no extension method 'State' accepting a first argument of type '[whatever return type I use]' could be found (are you missing a using directive or an assembly reference?)
我希望有人能帮我做一个假的DbContext.Entry方法。
通过"增加附加水平的间接性";我们得到:
public virtual void SetModified(object entity)
{
Entry(entity).State = EntityState.Modified;
}
并在控制器中使用CCD_ 4。mockContext.Setup(c=>c.SetModified(It.IsAny()));
为了解决这个问题,我增加了一个方法重载,并添加了一个过时的属性来查看原始方法的调用位置。
public virtual void Entry<TEntity>(TEntity entity, Action<DbEntityEntry<TEntity>> action) where TEntity : class
{
action(base.Entry(entity));
}
[Obsolete("Use overload for unit tests.")]
public new DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class
{
return base.Entry(entity);
/** or **/
throw new ApplicationException("Use overload for unit tests.");
}
则可以DbContext.Entry(order, ent => ent.State = EntityState.Modified;
如何实现基于接口的存储库和工作单元以获得所需内容的示例:
public interface IRepository<T>
{
T FindSingle(Expression<Func<T, Boolean>> predicate, params Expression<Func<T, object>>[] includeExpressions);
void ProxyGenerationOn();
void ProxyGenerationOff();
void Detach(T entity);
void Add(T newEntity);
void Modify(T entity);
void Attach(T entity);
void Remove(T entity);
void SetCurrentValues(T modifiedEntity, T origEntity);
T GetById(int id);
T GetById(int id, bool sealOverride);
IQueryable<T> GetAll();
IQueryable<T> GetAll(bool sealOverride);
IQueryable<T> GetAll(string[] EagerLoadPaths);
IQueryable<T> Find(Expression<Func<T, Boolean>> predicate);
}
public interface IUnitOfWork : IDisposable
{
//repository implementations go here
bool SaveChanges()
}
注意上下文是如何被完全抽象掉的。您只需要在具体实现中担心它。
您可以使用DbContext.Update(entity)
。就我而言,它运行良好,因为我嘲笑了DbContext
。
_dbContext.Update(entity);