Как я могу обнаружить изменения IDbSet
Я создаю фиктивный 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 мог знать, что объект отчета, который он возвратил, изменился?? Я знаю, что с помощью Entity Framework это возможно, но я понятия не имею, как...
1 ответ
Я думаю, что вы в основном там, но я бы предложил использовать насмешливый фреймворк, такой как Moq (мои личные предпочтения) или Rhino Mocks, чтобы высмеивать IReportContext
для ваших модульных тестов, вместо того, чтобы создавать проблемы типа Fake вроде MockReportContext
, (Хорошо, изучение фальшивых фреймворков сопряжено с некоторыми трудностями, но в будущем это избавит от рутинной работы с поддельными классами.)
Я бы предположил, что вы юнит тестирование кода, который зависит от IReportContext
так что вам не нужно ничего делать внутри SaveChanges()
, вам просто нужно подтвердить, что ваш код вызывал SaveChanges()
внутренне, если это предполагалось.
Вот хороший обзор использования Moq с производными классами DbContext / DbSet Entity Framework.
В приведенном выше связанном обзоре, если в конце модульное тестирование тестировало метод, который вызывает внутренне SaveChanges()
, это может дополнительно проверить, что SaveChanges()
действительно был вызван вашим методом со строкой:
dc.Verify(db => db.SaveChanges());
Вы также можете сделать это с вашим MockReportContext
класс, установив для свойства side значение True внутри SaveChanges()
Класс и проверка его в конце вашего модульного теста, но фреймворк гораздо более гибок и избавит от необходимости писать дополнительные классы для модульных тестов.
Если вы хотите избежать использования фальшивых фреймворков, то вот как это сделать с помощью подделок.