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

    @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 с тем которое получил в ходе тестирования и если они отличаются то тест не пройден

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

    @saxer Автор вопроса
    ну собственно оказалось все просто , сперва нужно создавать List со всеми объектами которые необходимо добавить, а потом делать context.AddRange
    var tmp = new List<Page>();
                for (int i = 0; i < data.Rows.Count; i++)
                {
                    ClearCurrentConsoleLine(menuBaseString.Length, menuBaseString.Length + 1);
                    Console.Write(i + "\\" + data.Rows.Count);
                    var row = data.Rows[i];
                    tmp.Add(new Page()
                    {
                        //...
                        Catalog_Id = Convert.ToInt32(row.ItemArray[2]),
                        CatalogName = row.ItemArray[3].ToString(),
                        CatalogIdentifer = row.ItemArray[4].ToString(),
                       //...
                    });
                }
    context.Pages.AddRange(tmp);


    итого вместо 2 часов , 4 мин
    Ответ написан
    Комментировать
  • Как создать интерфейс который бы реализовывал в объекте его конструктор?

    @saxer Автор вопроса
    Отвечаю на свой собственный вопрос, может кому то в будущем пригодится.
    Поскольку у меня была задача передавать в конструктор идентификатор пользователя то я реализовал это через httpContext, если нужно передавать что либо другое то думаю переделать особого труда не составит кому нужно, итак имеем интерфейс:
    public interface IBidInterface
        {
            void AddBid(BidDto bidDto,List<GoodDto> goodDto);
        }


    его реализация:
    public class BidLogic : IBidInterface
        {
            private readonly xyzContext _context;
            private readonly User _user;
    
            public BidLogic(string userId)
            {
                _context = new xyzContext();
                _user = new ApplicationUserManager(new UserStore<User>(_context)).FindById(userId);
            }
            public void AddBid(BidDto bidDto, List<GoodDto> goodDto)
            {
               //...
            }


    добавляем в NinjectDependencyResolver следующее:
    private void AddBindings()
            {
                kernel.Bind<IBidInterface>().To<BidLogic>().WithConstructorArgument("userId",GetUser);
            }
            private static object GetUser(IContext context)
            {
                var httpContext = context.Kernel.Get<HttpContextBase>();
                if (httpContext != null && httpContext.Session != null)
                {
                    var arg = httpContext.User.Identity.GetUserId();
                    if (arg != null && !string.IsNullOrEmpty(arg))
                    {
                        return arg;
                    }
                }
                return null;
            }


    все....теперь в конструктор будет передаваться значение userId
    Ответ написан
    Комментировать
  • Можно ли настроить nginx так, что бы он сохранял куки запроса к серверу, а потом восстанавливал их в ответе от бэкенда?

    @saxer Автор вопроса
    у меня стоит связка nginx->varnish->apache
    varnish обеспечивает кэширование, но он кэширует только те запросы которые приходят от apache без кук вообще иначе он их не кэширует, поэтому мне нужно сохранить в nginx куки сессии пользователя(по ним потом ajax ом я подружу корзину товаров итд), после этого очищаем все куки и передаем на varnish если у него в кэше этой страницы нет то он перенаправляет запрос на apache apache отдает страницу(без кук), varnish ee записывает в кэш и отдает nginx он в свою очередь добавляет к ней сохраненные на первом этапе куки сессии пользователя, при повторном обращении другого пользователя к этой же странице varnish уже не обратиться к apache а вернет кэшированную страницу к которой nginx должен добавить куки пользователя который к ней обратится, такая вот собственно задумка
    Ответ написан
    Комментировать