Я пытаюсь протестировать свой репозиторий, используя фиктивный контекст в памяти.
Я реализую это с помощью словаря в памяти, как и большинство людей. Это реализует элементы в моем интерфейсе репозитория для добавления, удаления, поиска и т. Д., Работая с коллекцией в памяти.
Это прекрасно работает в большинстве сценариев:
[TestMethod]
public void CanAddPost()
{
IRepository<Post> repo = new MockRepository<Post>();
repo.Add(new Post { Title = "foo" });
var postJustAdded = repo.Find(t => t.Title == "foo").SingleOrDefault();
Assert.IsNotNull(postJustAdded); // passes
}
Тем не менее, у меня есть следующий тест, который я не могу пройти с фиктивным репозиторием (прекрасно работает для репозитория SQL).
Считайте, что у меня есть три хранилища:
- Сообщения (обрабатывает сообщения с пользовательским контентом, например, вопрос StackOverflow).
- Места (места в мире, например, "Лос-Анджелес").
- LocationPosts (таблица соединений для обработки много-много между сообщениями / местоположениями).
Сообщения могут быть добавлены в никуда, или они также могут быть добавлены с определенным местоположением.
Вот мой тест:
[TestMethod]
public void CanAddPostToLocation()
{
var location = locationRepository.FindSingle(1); // Get LA
var post = new Post { Title = "foo", Location = location }; // Create post, with LA as Location.
postRepository.Add(post); // Add Post to repository
var allPostsForLocation = locationPostRepository.FindAll(1); // Get all LA posts.
Assert.IsTrue(allPostsForLocation.Contains(post)); // works for EF, fails for Mock.
}
По сути, при использовании «настоящего» EF / SQL-репозитория, когда я добавляю сообщение в определенное местоположение, EntityFramework достаточно умен, чтобы добавить запись «LocationPost», из-за ассоциации в EDMX (навигация «LocationPosts») собственность на объект "Почта")
Но как я могу сделать мой репозиторий Mock достаточно умным, чтобы "подражать" этому интеллекту EF?
Когда я делаю «Добавить» в моём репозитории, это просто добавляет в словарь. У него нет смысла говорить: «О, подожди, у тебя есть зависимая ассоциация, позволь мне добавить это в ДРУГОЙ репозиторий для тебя».
Мой Mock Repository является общим, поэтому я не знаю, как поместить туда смарты.
Я также смотрел на создание FakeObjectContext / FakeObjectSet (как советовала Джули Лерман в ее блоге), но это все еще не охватывает этот сценарий.
У меня такое чувство, что моё решение недостаточно хорошо. Может кто-нибудь помочь или предоставить актуальную статью о том, как правильно смоделировать репозиторий Entity Framework 4 / SQL Server, охватывающий мой сценарий?
Проблема core в том, что у меня есть один репозиторий на совокупный корень (что хорошо, но также и мое падение).
Итак Пост и Местоположение оба являются агрегированными корнями, но не владеют LocationPosts .
Таким образом, они представляют собой 3 отдельных хранилища, а в сценарии в памяти - 3 отдельных словаря. Я думаю, что мне не хватает «клея» между ними в моем репо в памяти.
EDIT
Отчасти проблема в том, что я использую Pure POCO (без генерации кода EF). У меня также нет отслеживания изменений (нет отслеживания на основе снимков, нет прокси-классов).
У меня сложилось впечатление, что именно здесь происходят "смарты".
В данный момент я изучаю опцию делегата. Я выставляю событие в моем Generic Mock Repository (void, принимает generic T, являющееся Entity), которое я вызываю после «Add». Затем я подписываюсь на это событие в моем «Репозитории сообщений», где я планирую добавить связанные объекты в другие репозитории.
Это должно работать. В качестве ответа поставлю в качестве ответа.
Однако я не уверен, что это лучшее решение, но опять же, это только для удовлетворения насмешек (код не будет использоваться для реальной функциональности).