Я пытаюсь разобраться с Поблочным тестированием очень простой ASP.NET тестовое приложение MVC, я создал использование Кода, Сначала приближаются в последнем EF4 CTP. Я не очень опыт с Поблочным тестированием / дразнящий и т.д.
Это - мой класс Репозитория:
public class WeightTrackerRepository
{
public WeightTrackerRepository()
{
_context = new WeightTrackerContext();
}
public WeightTrackerRepository(IWeightTrackerContext context)
{
_context = context;
}
IWeightTrackerContext _context;
public List<WeightEntry> GetAllWeightEntries()
{
return _context.WeightEntries.ToList();
}
public WeightEntry AddWeightEntry(WeightEntry entry)
{
_context.WeightEntries.Add(entry);
_context.SaveChanges();
return entry;
}
}
Это - IWeightTrackerContext
public interface IWeightTrackerContext
{
DbSet<WeightEntry> WeightEntries { get; set; }
int SaveChanges();
}
... и его реализация, WeightTrackerContext
public class WeightTrackerContext : DbContext, IWeightTrackerContext
{
public DbSet<WeightEntry> WeightEntries { get; set; }
}
В моем тесте у меня есть следующее:
[TestMethod]
public void Get_All_Weight_Entries_Returns_All_Weight_Entries()
{
// Arrange
WeightTrackerRepository repos = new WeightTrackerRepository(new MockWeightTrackerContext());
// Act
List<WeightEntry> entries = repos.GetAllWeightEntries();
// Assert
Assert.AreEqual(5, entries.Count);
}
И мой MockWeightTrackerContext:
class MockWeightTrackerContext : IWeightTrackerContext
{
public MockWeightTrackerContext()
{
WeightEntries = new DbSet<WeightEntry>();
WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("01/06/2010"), Id = 1, WeightInGrams = 11200 });
WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("08/06/2010"), Id = 2, WeightInGrams = 11150 });
WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("15/06/2010"), Id = 3, WeightInGrams = 11120 });
WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("22/06/2010"), Id = 4, WeightInGrams = 11100 });
WeightEntries.Add(new WeightEntry() { Date = DateTime.Parse("29/06/2010"), Id = 5, WeightInGrams = 11080 });
}
public DbSet<WeightEntry> WeightEntries { get;set; }
public int SaveChanges()
{
throw new NotImplementedException();
}
}
Моя проблема происходит, когда я пытаюсь создать некоторые данные тестирования, поскольку я не могу создать a DbSet<>
поскольку это не имеет никакого конструктора. Я получаю чувство, что я рявкаю неправильное дерево со своим целым подходом, пытающимся дразнить мой контекст. Любой совет нравился бы этому полному новичку поблочного тестирования.
Вы создаете DbSet с помощью фабричного метода Set () в контексте, но вам не нужна зависимость от EF в модульном тесте. Следовательно, вам необходимо реализовать заглушку DbSet с использованием интерфейса IDbSet или заглушку с использованием одной из фреймворков Mocking, таких как Moq или RhinoMock. Предполагая, что вы написали свою собственную заглушку, вам нужно просто добавить объекты WeightEntry во внутренний хэш-набор.
Возможно, вам повезет больше узнать о модульном тестировании EF, если вы будете искать ObjectSet и IObjectSet. Это аналоги DbSet до выпуска первого кода CTP, и о них написано гораздо больше с точки зрения модульного тестирования.
Вот отличная статья на MSDN, в которой обсуждается тестируемость кода EF. Он использует IObjectSet, но я думаю, что он по-прежнему актуален.
В ответ на комментарий Дэвида я добавляю это дополнение ниже, поскольку оно не помещается в -комментарии. Не уверены, что это лучший способ для ответов на длинные комментарии?
Вам следует изменить интерфейс IWeightTrackerContext, чтобы он возвращал IDbSet из свойства WeightEntries, а не конкретный тип DbSet. Затем вы можете создать MockContext либо с помощью фреймворка для имитации (рекомендуется), либо с помощью собственной настраиваемой заглушки.Это вернет StubDbSet из свойства WeightEntries.
Теперь у вас также будет код (например, пользовательские репозитории), который зависит от IWeightTrackerContext, который в процессе производства вы передадите в свой Entity Framework WeightTrackerContext, который будет реализовывать IWeightTrackerContext. Обычно это делается посредством внедрения конструктора с использованием инфраструктуры IoC, такой как Unity. Для тестирования кода репозитория, который зависит от EF, вы должны передать свою реализацию MockContext, чтобы тестируемый код считал, что он обращается к «реальным» EF и базой данных, и ведет себя (надеюсь), как ожидалось. Поскольку вы удалили зависимость от изменяемой внешней системы БД и EF, вы можете надежно проверять вызовы репозитория в своих модульных тестах.
Большая часть фреймворков имитаторов предоставляет возможность проверять вызовы имитирующих объектов для тестирования поведения. В приведенном выше примере ваш тест на самом деле тестирует только функциональность DbSet Add, которая не должна вас беспокоить, поскольку у MS будут модульные тесты для этого. Что вы хотели бы знать, так это то, что вызов Add on DbSet был сделан из кода вашего собственного репозитория, если это необходимо, и именно здесь на помощь приходят фреймворки Mock.
Извините, я знаю, что это много для переваривания, но если вы прочтете эту статью, и многое станет яснее, поскольку Скотт Аллен намного лучше объясняет эти вещи, чем я :)