我正在创建一个模拟IDbSet,以允许实体框架类的单元测试,等等。
然而,我确实无法检测到变化,甚至根本无法弄清楚如何去做。到目前为止,这是我的课程......
public interface IReportContext
{
IDbSet<Report> Reports {get;}
public int SaveChanges();
}
public class MockReportContext : IReportContext
{
IDbSet<Report> Reports {get;}
public int SaveChanges()
{
//Need to detect changes here???
}
public MockReportContext()
{
Reports = new MockDbSet<Report>();
}
}
public class MockDbSet<T> : IDbSet<T>
{
readonly ObservableCollection<T> _data;
readonly IQueryable _query;
public FakeDbSet()
{
_data = new ObservableCollection<T>();
_query = _data.AsQueryable();
}
public FakeDbSet(ObservableCollection<T> data)
{
_data = data;
_query = _data.AsQueryable();
}
public virtual T Find(params object[] keyValues)
{
throw new NotImplementedException();
}
public T Add(T item)
{
_data.Add(item);
return item;
}
public T Remove(T item)
{
_data.Remove(item);
return item;
}
public T Attach(T item)
{
_data.Add(item);
return item;
}
public T Detach(T item)
{
_data.Remove(item);
return item;
}
public T Create()
{
return Activator.CreateInstance<T>();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
return Activator.CreateInstance<TDerivedEntity>();
}
public ObservableCollection<T> Local
{
get { return _data; }
}
Type IQueryable.ElementType
{
get { return _query.ElementType; }
}
System.Linq.Expressions.Expression IQueryable.Expression
{
get { return _query.Expression; }
}
IQueryProvider IQueryable.Provider
{
get { return _query.Provider; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return _data.GetEnumerator();
}
}
这适用于添加,删除和检索实体。但是,当我尝试以下内容时:
IReportContext context = new MockReportContext();
context.Reports.Add(new Report()); //Works
Report report = context.Reports.First(); //Works
report.Message = "Hello World!";
context.SaveChanges(); //Does nothing
MockReportContext如何知道它返回的报表对象已经改变了?我知道使用实体框架这样做所以它必须是可能的,但我还没有弄清楚如何......
答案 0 :(得分:0)
我认为你主要在那里,但我建议使用像Moq(我的个人偏好)或Rhino Mocks这样的模拟框架来嘲笑IReportContext
你的单元测试,而不是像MockReportContext
那样创建Fake类的麻烦。 (好吧,学习一个模拟框架确实会带来一些麻烦,但它会在路上节省很多假的苦差事。)
我认为您要对依赖于IReportContext
的代码进行单元测试,因此您不需要在SaveChanges()
内执行任何操作,您只需断言你的代码确实在内部调用SaveChanges()
,如果它应该的话。
Here's a good overview使用Moq和Entity Framework的派生DbContext / DbSet类。
在上面的链接概述中,如果最后的单元测试是在测试内部调用SaveChanges()
的方法,则可以另外验证您的方法确实调用了SaveChanges()
: / p>
dc.Verify(db => db.SaveChanges());
您也可以通过在MockReportContext
类中将side属性设置为True并在单元测试结束时进行检查来对SaveChanges()
类执行此操作,但模拟框架更灵活并且将节省为单元测试编写额外类的需要。
如果您想避免使用模拟框架,请访问how to do it with fakes。