Как использовать библиотеку "Pex и Moles" с Entity Framework?
Это тяжелая, потому что не так много людей используют Pex и Moles или, я думаю, (хотя Pex - действительно отличный продукт - намного лучше, чем любой другой инструмент для тестирования единиц)
У меня есть проект Данные, который имеет очень простую модель с одним объектом (DBItem
). Я также написал DBRepository
в этом проекте, который управляет этой моделью EF. У репозитория есть метод под названием GetItems()
, который возвращает список элементов бизнес-уровня (BLItem
) и выглядит аналогично этому (упрощенный пример):
public IList<BLItem> GetItems()
{
using (var ctx = new EFContext("name=MyWebConfigConnectionName"))
{
DateTime limit = DateTime.Today.AddDays(-10);
IList<DBItem> result = ctx.Items.Where(i => i.Changed > limit).ToList();
return result.ConvertAll(i => i.ToBusinessObject());
}
}
Итак, теперь я хотел бы создать некоторые модульные тесты для этого конкретного метода. Я использую Pex и Moles. Я создал свои молы и заглушки для моего контекста объектов EF.
Я хотел бы написать параметризованный unit test (я знаю, что сначала написал свой производственный код, но мне пришлось, поскольку я тестирую Pex и Moles), который проверяет, что этот метод возвращает допустимый список элементов.
Это мой тестовый класс:
[PexClass]
public class RepoTest
{
[PexMethod]
public void GetItemsTest(ObjectSet<DBItem> items)
{
MEFContext.ConstructorString = (@this, name) => {
var mole = new SEFContext();
};
DBRepository repo = new DBRepository();
IList<BLItem> result = repo.GetItems();
IList<DBItem> manual = items.Where(i => i.Changed > DateTime.Today.AddDays(-10));
if (result.Count != manual.Count)
{
throw new Exception();
}
}
}
Затем я запускаю Pex Explorations для этого параметра, параметризованного unit test, но я получаю ошибку границы пути превышены. Pex запускает этот тест, предоставляя null
этому методу тестирования (так items = null
). Это код, который работает Pex:
[Test]
[PexGeneratedBy(typeof(RepoTest))]
[Ignore("the test state was: path bounds exceeded")]
public void DBRepository_GetTasks22301()
{
this.GetItemsTest((ObjectSet<DBItem>)null);
}
Это был дополнительный комментарий, предоставленный Pex:
Тестовый случай слишком длился для этих входов, и Pex остановил анализ. Обратите внимание: метод Oblivious.Data.Test.Repositories.TaskRepositoryTest.b__0 был вызван 50 раз; убедитесь, что код не застревает в бесконечном цикле или рекурсии. В противном случае нажмите "Установить MaxStack = 200" и снова запустите Pex.
Обновить атрибут [PexMethod (MaxStack = 200)]
Вопрос
Я делаю это правильно или нет? Должен ли я использовать заглушку EFContext? Должен ли я добавлять дополнительные атрибуты к методу тестирования, так что хозяин Moles будет работать (я не уверен, что это сейчас). Я бегу только Pex и Moles. Нет VS-теста или nUnit или что-то еще.
Думаю, я должен, вероятно, установить некоторое ограничение на Pex, сколько элементов он должен предоставить для этого конкретного метода тестирования.
Ответы
Ответ 1
Moles не предназначен для тестирования частей вашего приложения, которые имеют внешние зависимости (например, доступ к файлам, доступ к сети, доступ к базе данных и т.д.). Вместо этого Moles позволяет вам издеваться над этими частями вашего приложения, чтобы вы могли выполнять истинное модульное тестирование на частях, не имеющих внешних зависимостей.
Итак, я думаю, вы должны просто издеваться над вашими объектами и запросами EF, например, создавая списки в памяти и методы запросов возвращают поддельные данные из этих списков на основе любых критериев.
Ответ 2
Я просто разбираюсь с pex также... мои проблемы окружали меня, желая использовать его с moq;)
в любом случае...
У меня есть некоторые методы, похожие на ваши, которые имеют одинаковую проблему. Когда я увеличил максимум, они ушли. Предположительно, pex был удовлетворен тем, что он достаточно исследовал ветки. У меня есть методы, в которых мне также пришлось увеличивать время ожидания проверки кода.
Одна вещь, которую вы, вероятно, должны быть doign, хотя и передаёт во всех зависимых объектах в качестве параметров... т.е. не создавайте экземпляр репо в методе, а передавайте его.
Общая проблема заключается в том, что вы создаете большие объекты в своем методе. Я делаю то же самое в своих классах DAL, но тогда я не подхожу к unit test их изолированно. Я создаю наборы данных и использую это для проверки кода доступа к данным.
Я использую pex для своей бизнес-логики и объектов.
Если бы я попытался проверить мой идентификатор кода DAL, я должен использовать IOC для передачи datacontext в методы, которые затем сделают возможным тестирование, поскольку вы можете издеваться над контекстом данных.
Ответ 3
Вы должны использовать шаблон репозитория платформы Entity Framework: http://www.codeproject.com/KB/database/ImplRepositoryPatternEF.aspx