@saxer

Как правильно тестировать слой бизнес логики N-Layer?

Допустим у нас есть слой DAL в котором корректно настроена работа с БД через EntityFrimwork т.к. в нем описаны модели таблиц, определен контекст итд.
Далее создаем слой BAL в котором определены классы DTO моделей созданных в DAL.
Создаем класс репозитория допустим для "Товара":
public class ProductAdmRepository
{
public ProductDto Add(ProductDto productDto)
{
    using (var context = new SomeContext())
    {
        var product = new Product();
       // тут некоторая логика по формированию Product
       context.Products.Add(product);
       context.SaveChanges();
    }
}
}

Вопрос следующий , у меня добавление товара достаточно сложная операция которая добавляет в бд не только запись о самом товаре но например ссылку на изображение, его цену и прочее т.е. эта операция работает не с одной единственной таблицей в БД.
Сейчас для того что бы протестировать функционал у меня создан отдельный проект в котором я создаю DTO товара и добавляю его потом смотрю в что было добавлено и изменено в базе данных.
Как правильно организовать тестирование такой системы?
При модульном тестировании у меня не происходит запись в бд(или я не знаю как правильно настроить что бы запись происходила?), при этом я вижу что в контексте были созданы объекты(и они даже остаются сохраненными в нем при повторном запуске теста, как будто я работаю с копией реальной БД), но эти объекты не были сохранены в БД.
И я не понимаю как мне правильно организовать тестирование что бы например проверить правильно ли был добавлен товар в систему.
  • Вопрос задан
  • 352 просмотра
Пригласить эксперта
Ответы на вопрос 2
RyzhovAlexandr
@RyzhovAlexandr
люблю .NET, интересуюсь также Java, BigData
Для тестирования репозитория, если он полностью использует для сохранения и доступа к данным только методы EntityFramework, можно не использовать реальную базу, а воспользоваться Effort. Но для этого необходимо создать тестовый DbContext, который бы использовал эту библиотеку. В вашем примере не очень понятно с какой БД вы работаете, т.к. если у вас в app.config нет ConnectionString, то не совсем понятно как работает ваш тест.

Если же для работы с БД репозиторий использует ExecuteQuery, то Effort - не подойдет, придется использовать реальную БД - но это уже можно сказать интеграционные тесты. В них есть плюс - что они более приближены к реальным сценариям, но минус - более тяжелы в поддержке.
Ответ написан
Комментировать
@saxer Автор вопроса
Хорошо. Тогда придется написать побольше кода.
Итак у нас есть например следующие модели:
1) Product - товар
2) MaterialGroup - группа материалов
3) Price - цена товара в зависимости от группы материалов(или просто цена если группа не определена)
Код моделей:
public class Product
    {
        //main
        public int Id { get; set; }
        public string Name { get; set; }
        //....
        //prices
        public List<Price> Prices { get; set; } 
        public int CalcPrice {get;set;}
    }
public class MaterialGroup
    {
        public int MaterialGroupId { get; set; }
        public string Name { get; set; }
        ///.....
    }
public class Price
    {
        public int PriceId { get; set; }
        public Product.Product Product { get; set; }
        public MaterialGroup MaterialGroup { get; set; }
        public int BasePrice { get; set; }
    }

Так же имеем модели DTO по типу ProductDto, PriceDto и.т.д. которые полностью копируют базовые модели.
Теперь создаем репозиторий:
public class ProductAdmRepository
    {
        public ProductDto Add(ProductDto productDto)
            {
                using (var context = new SomeContext())
                {
                    try
                    {
                    var product = new Product();
                     // тут некоторая логика по формированию Product
                     // например если у товара несколько групп материалов и для каждого своя цена
                     // то мы вычисляем минимальную и приравниваем Product.CalcPrice к ней
                    context.Products.Add(product);
                    context.SaveChanges();
                    var productDto = new ProductDto();
                    //тут происходит маппинг product в productDto
                    //return productDto;
                    }
                    catch (Exception)
                    {
                         return null;                      
                    }
                }                    
            }
    }
Тест:
[TestMethod]
public void TestDeb()
        {
            var userProductDto = new ProductDto()
            {
                Name = "Product with materials",
                PriceDtos = new List<PriceDto>()
                {
                    new PriceDto() {MaterialGroupDto = new MaterialGroupDto() {MaterialGroupId = 1}, Price = 100},
                    new PriceDto() {MaterialGroupDto = new MaterialGroupDto() {MaterialGroupId = 2}, Price = 200},
                }
            };
            var assertProduct = new ProductDto()
            {
                //...то что должны получить на выходе
                CalcPrice = 100
            };
            var repo = new ProductAdmRepository();
            var newProduct = repo.Add(userProductDto);
            Assert.IsTrue(newProduct.Equals(assertProduct));
        }

Т.е. суть в том что я определяю в тесте 2 dto:
1) Которое будет имитировать введенные пользователем данные
2) Второе которое должно быть получено после того как система обработало первое dto
3) Сравниваю второе dto с тем которое получил в ходе тестирования и если они отличаются то тест не пройден

В чем проблема, поскольку репозиторий работает с реальной БД , а тест нет, то при проверке на добавление товара метод добавления не может получить например сущности групп материалов на основе которых он создаст сущность цены.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы