Как я могу обнаружить изменения 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 делает это, поэтому это должно быть возможно, но я понятия не имею, как...


person Nick Williams    schedule 10.01.2014    source источник


Ответы (1)


Я думаю, вы в основном там, но я бы предложил использовать фиктивный фреймворк, такой как Moq (мой личный предпочтения) или Rhino Mocks, чтобы имитировать IReportContext для ваших модульных тестов, вместо того, чтобы утруждать себя создания класса Fake, такого как MockReportContext. (Хорошо, изучение мок-фреймворка сопряжено с некоторыми трудностями, но это избавит вас от рутинной работы с классом Fake в будущем.)

Я бы предположил, что вы выполняете модульное тестирование кода, который зависит от IReportContext, поэтому вам не нужно ничего делать внутри SaveChanges(), вам просто нужно подтвердить, что ваш код вызывал SaveChanges() внутри, если это предполагалось.

Вот хороший обзор использования Moq с производными от Entity Framework классами DbContext/DbSet.

В приведенном выше связанном обзоре, если модульный тест в конце тестировал метод, который внутренне вызывает SaveChanges(), он мог бы дополнительно проверить, что SaveChanges() действительно был вызван вашим методом, с помощью строки:

dc.Verify(db => db.SaveChanges());

Вы также можете сделать это с вашим классом MockReportContext, установив для свойства side значение True внутри класса SaveChanges() и проверив его в конце вашего модульного теста, но фиктивная структура гораздо более гибкая и избавит от необходимости писать дополнительные классы для модуля. тесты.

Если вы не хотите использовать фиктивный фреймворк, вот как это сделать с подделками.

person MCattle    schedule 17.03.2014