Поддельный DbContext для платформы Entity Framework 4.1 для тестирования

Я использую этот учебник для подделки моего DbContext и теста: http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic -repository /

Но мне нужно изменить реализацию FakeMainModuleContext для использования в моих controllerах:

public class FakeQuestiona2011Context : IQuestiona2011Context { private IDbSet _credencial; private IDbSet _perfil; private IDbSet _apurador; private IDbSet _entrevistado; private IDbSet _setor; private IDbSet _secretaria; private IDbSet _pesquisa; private IDbSet _pergunta; private IDbSet _resposta; public IDbSet Credencial { get { return _credencial ?? (_credencial = new FakeDbSet()); } set { } } public IDbSet Perfil { get { return _perfil ?? (_perfil = new FakeDbSet()); } set { } } public IDbSet Apurador { get { return _apurador ?? (_apurador = new FakeDbSet()); } set { } } public IDbSet Entrevistado { get { return _entrevistado ?? (_entrevistado = new FakeDbSet()); } set { } } public IDbSet Setor { get { return _setor ?? (_setor = new FakeDbSet()); } set { } } public IDbSet Secretaria { get { return _secretaria ?? (_secretaria = new FakeDbSet()); } set { } } public IDbSet Pesquisa { get { return _pesquisa ?? (_pesquisa = new FakeDbSet()); } set { } } public IDbSet Pergunta { get { return _pergunta ?? (_pergunta = new FakeDbSet()); } set { } } public IDbSet Resposta { get { return _resposta ?? (_resposta = new FakeDbSet()); } set { } } public void SaveChanges() { // do nothing (probably set a variable as saved for testing) } } 

И мой тест:

 [TestMethod] public void IndexTest() { IQuestiona2011Context fakeContext = new FakeQuestiona2011Context(); var mockAuthenticationService = new Mock(); var apuradores = new List { new Apurador() { Matricula = "1234", Nome = "Acaz Souza Pereira", Email = "acaz@telecom.inf.br", Ramal = "1234" }, new Apurador() { Matricula = "4321", Nome = "Samla Souza Pereira", Email = "samla@telecom.inf.br", Ramal = "4321" }, new Apurador() { Matricula = "4213", Nome = "Valderli Souza Pereira", Email = "valderli@telecom.inf.br", Ramal = "4213" } }; apuradores.ForEach(apurador => fakeContext.Apurador.Add(apurador)); ApuradorController apuradorController = new ApuradorController(fakeContext, mockAuthenticationService.Object); ActionResult actionResult = apuradorController.Index(); Assert.IsNotNull(actionResult); Assert.IsInstanceOfType(actionResult, typeof(ViewResult)); ViewResult viewResult = (ViewResult)actionResult; Assert.IsInstanceOfType(viewResult.ViewData.Model, typeof(IndexViewModel)); IndexViewModel indexViewModel = (IndexViewModel)viewResult.ViewData.Model; Assert.AreEqual(3, indexViewModel.Apuradores.Count); } 

Я делаю это правильно?

5 Solutions collect form web for “Поддельный DbContext для платформы Entity Framework 4.1 для тестирования”

К сожалению, вы не делаете это правильно, потому что эта статья неверна. Он притворяется, что FakeContext сделает ваш блок кода тестируемым, но он не будет. После того, как вы IDbSet или IQueryable на свой controller, и вы подделываете набор с помощью коллекции памяти, вы никогда не сможете быть уверены, что ваш модульный тест действительно проверяет ваш код. Очень легко написать запрос LINQ в controllerе, который пройдет ваш модульный тест (потому что FakeContext использует LINQ-to-Objects), но не работает во время выполнения (потому что ваш реальный контекст использует LINQ-to-Entities). Это делает всю цель вашей единицы тестирования бесполезной.

Мое мнение: Не беспокойтесь о фальшивом контексте, если вы хотите разоблачить наборы controllerов. Вместо этого используйте тесты интеграции с реальной базой данных для тестирования. Это единственный способ проверить, что запросы LINQ, определенные в controllerе, выполняют то, что вы ожидаете.

Конечно, если вы хотите называть только ToList или FirstOrDefault на своих наборах, ваш FakeContext будет вам хорошо, но как только вы сделаете что-нибудь более сложное, вы можете скоро найти ловушку (просто поместите строку «Невозможно перевести в выражение хранилища» в Google – все эти проблемы появятся только при запуске Linq-to-entity, но они пройдут ваши тесты с помощью Linq-to-objects).

Это довольно распространенный вопрос, поэтому вы можете проверить некоторые другие примеры:

  • Чтобы вернуть IQueryable или не вернуть IQueryable
  • Единичное тестирование DbContext
  • Первая архитектура ASP.NET MVC3 и Entity Framework Code
  • Организационно, где я должен ставить общие запросы при первом использовании кода Entity Framework?
  • Можно ли заглушить контекст и classы Entity Framework для проверки уровня доступа к данным?

«К сожалению, вы не делаете это правильно, потому что эта статья неверна. Она притворяется, что FakeContext сделает ваш блок кода проверяемым, но он не будет”

Я создатель блога, на который вы ссылаетесь. Проблема, которую я вижу здесь, заключается в непонимании основ N-Layered модульного тестирования. Мой пост не предназначен для непосредственного использования для проверки логики controllerа.

Единичный тест должен выполняться точно так же, как следует из названия, и тестировать «Единое устройство». Если я тестирую controller (как вы это делаете выше), я забываю о доступе к данным. Я должен удалить все вызовы в контексте базы данных и заменить их вызовом метода черного ящика, как будто эти операции мне неизвестны. Это код вокруг этих операций, который мне интересен при тестировании.

Пример:

В моем приложении MVC мы используем шаблон репозитория. У меня есть repository, скажем CustomerRepository: ICustomerRepository, который будет выполнять все операции с моей клиентской базой данных.

Если бы я должен был проверить мои controllerы, я бы хотел, чтобы тесты тестировали мой repository, мой доступ к базе данных и сама логика controllerа? конечно нет! в этом трубопроводе много «единиц». То, что вы хотите сделать, – создать поддельный repository, который реализует ICustomerRepository, чтобы вы могли изолировать логику controllerа.

Это, насколько мне известно, не может быть сделано только в контексте базы данных. (за исключением, возможно, использования Microsoft Moles, который вы можете проверить, если хотите). Это просто потому, что все запросы выполняются вне контекста в вашем classе controllerа.

Если бы я хотел проверить логику CustomerRepository, как бы я это сделал? Самый простой способ – использовать поддельный контекст. Это позволит мне убедиться, что, когда я пытаюсь получить клиента по id, он фактически получает клиента по id и так далее. Методы репозитория очень просты и проблема «Не может быть переведена в хранилище» обычно не будет отображаться. Хотя в некоторых незначительных случаях он может (иногда из-за неправильно написанных запросов linq) в этих случаях важно также выполнять интеграционные тесты, которые будут полностью проверять ваш код до базы данных. Эти проблемы будут обнаружены при тестировании интеграции. Я уже давно использовал эту технику N-Layered и не нашел никаких проблем с этим.

Интеграционные тесты

Очевидно, тестирование вашего приложения против самой базы данных – дорогостоящее упражнение, и как только вы получите десятки тысяч тестов, это станет кошмаром, с другой стороны, лучше всего имитировать, как код будет использоваться в «реальном мире». Эти тесты также важны (от ui к базе данных), и они будут выполняться как часть интеграционных тестов, а не модульных тестов.

Acaz, что вам действительно нужно в вашем сценарии, это repository, который является макетным / поддельным. Если вы хотите проверить свои controllerы, как вы делаете, ваш controller должен взять объект, который обертывает функциональность базы данных. Затем он может вернуть все, что вам нужно, чтобы проверить все аспекты функциональности вашего controllerа.

см. http://msdn.microsoft.com/en-us/library/ff714955.aspx

Чтобы протестировать сам repository (обсуждаемый, если необходимо, во всех случаях), вы захотите либо подделать контекст, либо использовать что-то по строкам frameworks Moles.

LINQ трудно тестировать. Тот факт, что запрос определен вне контекста с использованием методов расширения, дает нам большую гибкость, но создает кошмар для тестирования. Оберните свой контекст в repository, и эта проблема исчезнет.

извините, так долго 🙂

Как отметил Ladislav Mrnka, вы должны протестировать Linq-to-Entity, но не Linq-to-Object. Я обычно использовал Sql CE как тестовую БД и всегда воссоздавал базу данных перед каждым тестом. Это может сделать тест немного медленным, но до сих пор у меня все в порядке с производительностью для моих более 100 модульных тестов.

Сначала измените настройку строки подключения с помощью SqlCe в App.config вашего тестового проекта.

    

Во-вторых, установите инициализатор db с помощью DropCreateDatabaseAlways .

 Database.SetInitializer(new DropCreateDatabaseAlways()); 

И затем, запустите EF для инициализации перед запуском каждого теста.

 public void Setup() { Database.SetInitializer(new DropCreateDatabaseAlways()); context = new MyDbContext(); context.Database.Initialize(force: true); } 

Если вы используете xunit, вызовите метод установки в своем конструкторе. Если вы используете MSTest, поставьте TestInitializeAttribute на этот метод. Если nunit …….

Вы можете создать Fake DbContext, используя Effort для EF 6+. См. https://effort.codeplex.com/ . Усилия направлены на выполнение работ по проектированию F ake O bjectContext R ealization T ool.

Для статьи с рабочим образцом см. http://www.codeproject.com/Tips/1036630/Using-Effort-Entity-Framework-Unit-Testing-Tool или http://www.codeproject.com/Articles/ 460175 / Two-strategy-for-testing-Entity-Framework-Effort? Msg = 5122027 # xx5122027xx .

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

Так как я должен был это сделать, я оставляю это здесь, это может помочь некоторым людям. Я совершенно новичок в c # / .net и все, поэтому далек от оптимизации / очистки, но, похоже, это работает.

следуя MSDN. Найдите здесь отсутствующий class и используя немного отражения. Мне удалось добавить односторонние свойства. Ключевыми элементами здесь являются AddNavigationProperty и RefreshNavigationProperties . Если у кого-то есть предложение улучшить этот код, я с радостью возьму их

 using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data.Entity; using System.Data.Entity.Infrastructure; using System.Linq; using System.Linq.Expressions; namespace MockFactory { public class TestDbSet : DbSet, IQueryable, IEnumerable, IDbAsyncEnumerable where TEntity : class { public readonly ObservableCollection _data; private readonly IQueryable _query; private readonly Dictionary entities; public TestDbSet() { _data = new ObservableCollection(); _query = _data.AsQueryable(); entities = new Dictionary(); } public override ObservableCollection Local { get { return _data; } } IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator() { return new TestDbAsyncEnumerator(_data.GetEnumerator()); } IEnumerator IEnumerable.GetEnumerator() { return _data.GetEnumerator(); } Type IQueryable.ElementType { get { return _query.ElementType; } } Expression IQueryable.Expression { get { return _query.Expression; } } IQueryProvider IQueryable.Provider { get { return new TestDbAsyncQueryProvider(_query.Provider); } } IEnumerator IEnumerable.GetEnumerator() { return _data.GetEnumerator(); } public void AddNavigationProperty(DbSet dbSet) where T : class { entities.Add(typeof (T), dbSet); } public void RefreshNavigationProperty(TEntity item) { foreach (var entity in entities) { var property = item.GetType().GetProperty(entity.Key.Name); var type = (int)item.GetType().GetProperty(entity.Key.Name.Replace(typeof(TEntity).Name, "")).GetValue(item); var dbSets = (IEnumerable)entity.Value.GetType().GetField("_data").GetValue(entity.Value); var dbSet = dbSets.Single(x => (int)x.GetType().GetProperty("Id").GetValue(x) == type); property.SetValue(item, dbSet); } } public override TEntity Add(TEntity item) { RefreshNavigationProperty(item); _data.Add(item); return item; } public override TEntity Remove(TEntity item) { _data.Remove(item); return item; } public override TEntity Attach(TEntity item) { _data.Add(item); return item; } public override TEntity Create() { return Activator.CreateInstance(); } public override TDerivedEntity Create() { return Activator.CreateInstance(); } } } 

Затем вы можете создать свой контекст

  public TestContext() { TypeUsers = new TestDbSet(); StatusUsers = new TestDbSet(); TypeUsers.Add(new TypeUser {Description = "FI", Id = 1}); TypeUsers.Add(new TypeUser {Description = "HR", Id = 2}); StatusUsers.Add(new StatusUser { Description = "Created", Id = 1 }); StatusUsers.Add(new StatusUser { Description = "Deleted", Id = 2 }); StatusUsers.Add(new StatusUser { Description = "PendingHR", Id = 3 }); Users = new TestDbSet(); ((TestDbSet) Users).AddNavigationProperty(StatusUsers); ((TestDbSet)Users).AddNavigationProperty(TypeUsers); } public override DbSet TypeUsers { get; set; } public override DbSet StatusUsers { get; set; } public override DbSet Users { get; set; } public int SaveChangesCount { get; private set; } public override int SaveChanges(string modifierId) { SaveChangesCount++; return 1; } } 

Наконец, не забудьте в своем тесте обновить свойства навигации, прежде чем делать assert (должен быть лучший способ, но я не мог его найти)

 ContextFactory.Entity.Users.Each(((TestDbSet) ContextFactory.Entity.Users).RefreshNavigationProperty); 
  • Очистка после всех тестов junit
  • Как я могу написать единичный тест, чтобы определить, можно ли собирать мусор?
  • Как проверить код, связанный с базой данных с NUnit?
  • Как подождать завершения асинхронного отправления?
  • Selenium many Logs (Как удалить)
  • Как утверждать равенство на двух classах без метода equals?
  • Единичное тестирование DbContext
  • Как обмануть repository async с помощью ядра Entity Framework
  • Может ли Google выманить метод с типом возвращаемого интеллектуального указателя?
  • Модульный ввод / вывод файлов
  • annotations, чтобы сделать приватный метод общедоступным только для тестовых classов
  • Interesting Posts

    Как вы получаете текущий номер страницы ViewPager для Android?

    Создание чата Bubble в Android

    Приложение для калькулятора Windows 10 не учитывает десятичный символ формата области

    Что такое «самый легкий» -> не возиться с антивирусом системного реестра

    Icecast 2: описание протокола, streamовое воспроизведение с использованием C #

    Что может быть причиной исключения System.TypeLoadException?

    Слушайте микрофон дистанционно

    Если клавиша клавиатуры ноутбука не работает, я должен вытащить ее и очистить ее основание?

    Фоновое изображение в ключевом кадре не отображается в Firefox или Internet Explorer

    Сложный тип получает значение null в параметре ApiController

    jQuery не работает после загрузки содержимого через AJAX

    Как установить стиль «Заголовок» в Word 2013?

    Как предотвратить создание объекта в куче?

    Что такое префикс L в C ++?

    вызов чистой виртуальной функции из конструктора базового classа

    Давайте будем гением компьютера.