Как писать тесты в asp.net mvc не затрагивая Entity Framework?

Как мокать EF не используя не нужный слой абстракции с репозиторями таким образом чтобы весь функционал EF оставался рабочим? Сейчас в тесте использую такой подход:

var mockSet = new Mock<DbSet<tarif>>();
            var data = new List<tarif>
            {
                new tarif { id = 1, name = "Entity 1" },
                new tarif { id = 2, name = "Entity 2" }
            }.AsQueryable();

            mockSet.As<IQueryable<tarif>>().Setup(m => m.Provider).Returns(data.Provider);
            mockSet.As<IQueryable<tarif>>().Setup(m => m.Expression).Returns(data.Expression);
            mockSet.As<IQueryable<tarif>>().Setup(m => m.ElementType).Returns(data.ElementType);
            mockSet.As<IQueryable<tarif>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

            var customDbContextMock = new Mock<callerEntities>();
            customDbContextMock.Setup(x => x.tarifs).Returns(mockSet.Object);


но не работают методы типа .Remove()
и как к примеру протестировать кусок кода в котором EF работает с хранимой процедурой?
Database.SqlQuery<GetSiteWidget_Result>("GetSiteWidgetAll").ToList()
  • Вопрос задан
  • 758 просмотров
Решения вопроса 1
@MADm Автор вопроса
Дописал мокирование remove, removerange, add, addrange и засунул в обобщенный метод
public static DbSet<T> MockDbSet<T>(List<T> table) where T : class
        {
            var dbSet = new Mock<DbSet<T>>();
            dbSet.As<IQueryable<T>>().Setup(q => q.Provider).Returns(() => table.AsQueryable().Provider);
            dbSet.As<IQueryable<T>>().Setup(q => q.Expression).Returns(() => table.AsQueryable().Expression);
            dbSet.As<IQueryable<T>>().Setup(q => q.ElementType).Returns(() => table.AsQueryable().ElementType);
            dbSet.As<IQueryable<T>>().Setup(q => q.GetEnumerator()).Returns(() => table.AsQueryable().GetEnumerator());
            dbSet.Setup(set => set.Add(It.IsAny<T>())).Callback<T>(table.Add);
            dbSet.Setup(set => set.AddRange(It.IsAny<IEnumerable<T>>())).Callback<IEnumerable<T>>(table.AddRange);
            dbSet.Setup(set => set.Remove(It.IsAny<T>())).Callback<T>(t => table.Remove(t));
            dbSet.Setup(set => set.RemoveRange(It.IsAny<IEnumerable<T>>())).Callback<IEnumerable<T>>(ts =>
            {
                foreach (var t in ts) { table.Remove(t); }
            });
            return dbSet.Object;
        }

Для моих нужд пока подходит.
Объясню почему мне не нравится подход с репозиториями. Если не использовать generic репозиторий тогда код вырастет в n раз на каждую таблицу. Тогда получается надо сделать generic потом унаследовать от него каждую сущность и получается что у нас куча репозиториев. Как к ним тогда обращатся? суем их в один класс и получаем тот самый dbcontext который генерит ef а репозитории в нем это теже dbset. Тоесть мы создаем абстракцию над абстракцией чтоб смогли от неё унаследовать методы для тестов. Смысл из такого кроме очевидных минусов потери части функционала контекста я не особо вижу.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
Nipheris
@Nipheris Куратор тега C#
Как мокать EF не используя не нужный слой абстракции с репозиторями таким образом чтобы весь функционал EF оставался рабочим?

Может, не такой он уж он не нужный? Репозиторий нужен в том числе для того, чтобы иметь четкий список методов для тестирования. Я сейчас вообще не могу толком понять, что вы тестируете.
Ответ написан
Комментировать
@Sing303
Вариант 1:
Использовать неограниченные фреймворки, на подобии Typemock, он позволит подделывать что угодно, приватные и статические методы

Вариант 2:
Использовать репозиторий. Необходимость использовать Typemock говорит о том, что код "плохо пахнет" и в нём явно что-то не так.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы