模拟包含库模式

时间:2019-03-28 12:55:41

标签: c# entity-framework moq

我一直在尝试统一测试使用存储库模式创建的查询,我似乎无法弄清楚这一点。看来我在这里一定做错了。

因此,我已经创建了一个通用存储库,其外观可能类似于:

 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 个答案:

答案 0 :(得分:1)

您遇到的问题是,当您想在存储库级别进行模拟时,由于您希望模拟出单独的DBSet,因此代码在尝试中变得过于深入,以至于被测代码将与IQueryable返回的期望是与其他模拟DbSet相关的DdSet。

即 给定一个客户包含一个用户:模拟一组期望的客户,模拟一组用户,然后调用代码以某种方式知道他们?

相反,就测试而言,您的存储库是您的边界。该存储库仅返回一个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”知道如何从另一组存根中解决问题)在测试情况下,.Include调用实际上被忽略了。它在EF中所做的全部工作是通知引擎在执行查询时获取相关数据,实际上并不会加载任何内容。

我还建议您为模拟的Queryable结果阅读实现IDbAsyncQueryProvider的内容,以便以后可以对存储库方法使用异步操作。 (即ToListAsync()等)(Unit-testing .ToListAsync() using an in-memory

答案 1 :(得分:0)

好的,我希望这对其他人有帮助,我实际上无法模拟include方法。因此,我最终要做的是制作一个继承自ICustomerRepository的{​​{1}}。然后,我仅添加了一个方法IRepository<Customer>并对其进行了模拟。