Ложное включение с шаблоном репозитория - PullRequest
0 голосов
/ 28 марта 2019

Я пытался протестировать единый запрос, который я создал, используя шаблон репозитория, но я не могу понять, что это. Похоже, я тут что-то не так делаю.

Итак, я создал общий репозиторий, который может выглядеть примерно так:

 public interface IRepository<T> where T:class,IEntity, new()
 {
      IQueryable<T> Get();

      T Get(int id);

      T Add(T entity);

      T Update(T entity);

      void Delete(int id);
 }

У меня также есть контекст, который может выглядеть следующим образом:

 public class ApplicationContext:DbContext
 {
      public virtual DbSet<Customer> Customers { get; set; }
      public virtual DbSet<User> Users { get; set; }
 }

так что теперь у меня, конечно, теперь есть хранилище, которое выглядит как IRepository<Customer> customersRepository.

В моем контроллере у меня есть запрос, который может выглядеть так:

          var customers = _customerRepository
               .Get()
               .Include(customer => customer.Users)
               .Where(customer=>customer.Status == "active")
               .ToList();

Итак, на мой вопрос, я хотел бы проверить это, но я получаю сообщение об ошибке

Значение не может быть нулевым

мой юнит-тест выглядит так:

      [TestMethod]
      public void GetCustomerList_ValidParameters_ShouldOnlyReturnItemsWithActiveStatus()
      {

           //Act
           var customers = _customerModel.GetCustomerList(
                _parentId, /*parentId*/
                string.Empty, /*keywords*/
                1, /*page*/
                20, /*count*/
                out var totalCount, /*totalCount*/
                null /*orderBy*/
           );

           //Assert
           Assert.AreEqual(expected:3, actual: customers.Count);
      }

мои настройки данных выглядят так:

      private void AddDataToRepository()
      {

           var customers = new List<Customer>()
           {
                new Customer{Id = Guid.NewGuid().ToString(), Name = "ABC", Status = "active", Parent_id = _parentId},
                new Customer{Id = Guid.NewGuid().ToString(), Name = "DEF", Status = "canceled", Parent_id = _parentId},
                new Customer{Id = Guid.NewGuid().ToString(), Name = "HIJ", Status = "active", Parent_id = _parentId},
                new Customer{Id = Guid.NewGuid().ToString(), Name = "MNO", Status = "suspended", Parent_id = _parentId},
                new Customer{Id = Guid.NewGuid().ToString(), Name = "QRS", Status = "active", Parent_id = _parentId},
           };

           var users = new List<User>();
           var usersMock = new Mock<DbSet<User>>();
           _customerRepositoryMock.Setup(x => x.Get().Include(It.IsAny(typeof(User))));

           _customerRepositoryMock.Setup(x => x.Get()).Returns(customers.ToDbSet());

      }

Как тут издеваться над пользователями.

Ответы [ 2 ]

1 голос
/ 29 марта 2019

Проблема, с которой вы столкнулись, заключается в том, что, хотя вы хотите макетировать на уровне хранилища, код пытается зайти слишком глубоко в том смысле, что вы ожидали макетировать отдельные наборы DBSets, чтобы тестируемый код взаимодействовал с IQueryable вернул ожидающий DdSet, который относится к другим поддельным DbSets.

т.е. Если Клиент содержит Пользователя: имитируйте ожидаемый набор клиентов, насмехайтесь над набором пользователей, тогда вызывающий код каким-то образом узнает о них?

Вместо этого ваш репозиторий является вашей границей в том, что касается теста. Хранилище просто возвращает IQueryable<Customer>, поэтому смоделированное хранилище должно отправить обратно набор клиентов с достаточным количеством информации, чтобы удовлетворить потребителя.

  private void AddDataToRepository()
  {
       var testUser = new User{ UserId = 1, UserName = "Me" };
       var customers = new List<Customer>()
       {

            new Customer{Id = Guid.NewGuid().ToString(), Name = "ABC", Status = "active", Parent_id = _parentId, User = testUser},
            new Customer{Id = Guid.NewGuid().ToString(), Name = "DEF", Status = "canceled", Parent_id = _parentId, User = testUser},
            new Customer{Id = Guid.NewGuid().ToString(), Name = "HIJ", Status = "active", Parent_id = _parentId, User = testUser},
            new Customer{Id = Guid.NewGuid().ToString(), Name = "MNO", Status = "suspended", Parent_id = _parentId, User = testUser},
            new Customer{Id = Guid.NewGuid().ToString(), Name = "QRS", Status = "active", Parent_id = _parentId, User = testUser},
       };

       _customerRepositoryMock.Setup(x => x.Get()).Returns(customers.AsQueryable());
 }

Проблема в том, что ваш код ожидает найти пользователя у вашего клиента, поэтому вам нужно инициализировать своего клиента-заглушку, чтобы получить ссылку на пользователя. (не ожидайте, что вызов «Включить» узнает, как это сделать из другого набора заглушек) Вызов .Include в случае теста фактически игнорируется. Все, что он делает в EF - это информирует движок о необходимости получения связанных данных, когда он выполняет запрос, он на самом деле ничего не загружает.

Я бы также порекомендовал прочитать о реализации IDbAsyncQueryProvider для ваших смоделированных результатов Queryable, чтобы впоследствии вы могли использовать асинхронные операции с вашими методами репозитория. (т.е. ToListAsync() и т. д.) ( Модульное тестирование .ToListAsync () с использованием находящейся в памяти )

0 голосов
/ 28 марта 2019

Хорошо, я надеюсь, что это поможет другим, я не смог на самом деле издеваться над методом включения. Итак, в итоге я сделал ICustomerRepository, унаследованный от IRepository<Customer>. Затем я просто добавил метод CustomersWithUsers и высмеял это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...