代码之家  ›  专栏  ›  技术社区  ›  Cybercop

单元测试:如何测试通用存储库

  •  3
  • Cybercop  · 技术社区  · 7 年前

    public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
    {
        protected readonly DbContext DbContext;
        public GenericRepository(DbContext dbContext)
        {
            DbContext = dbContext;
        }
    
        public string Create(T item)
        {
            if (string.IsNullOrEmpty(item.Id))
            {
                item.Id = Guid.NewGuid().ToString("N");
            }
            item.CreatedAt = DateTime.UtcNow;
            DbContext.Entry(item).State = EntityState.Added;
            DbContext.SaveChanges();
            return item.Id;
            /*using (var dbContext = new MyDbContext())
            {
                item.Id = Guid.NewGuid().ToString("N");
                item.CreatedAt = DateTime.UtcNow;
                dbContext.Entry(item).State = EntityState.Added;
                dbContext.SaveChanges();
                return item.Id;
            }*/
        }
        public T GetById(string id)
        {
            return GetFirst(x => x.Id == id);
        }      
    
        public T GetFirst(Expression<Func<T, bool>> @where, params Expression<Func<T, object>>[] nav)
        {
            return GetFiltered(nav).FirstOrDefault(where);
            /*using (var context = new MyDbContext())
            {
                return GetFiltered(context, nav).FirstOrDefault(where);
            }*/
        }
    
    
        private IQueryable<T> GetFiltered(params Expression<Func<T, object>>[] nav)
        {
            IQueryable<T> q = DbContext.Set<T>();
            return nav.Aggregate(q, (current, n) => current.Include(n));
        }
    
    }
    

    基于 microft's testing fundamental site 我试着写一些测试用例。

    下面是单元测试代码

    [TestClass]
    public class GenericRepositoryTest
    {
        private Foo _foo;
        private IQueryable<Foo> _fooList;
        private Mock<DbSet<Foo>> _mockSet;  
    
        [TestInitialize]
        public void Setup()
        {
            _foo = new Foo
            {            
                EmailId = "foo@bar.com",
                FirstName = "foo",
                LastName = "bar",               
                ProfileId = 27,
                IsDeleted = false,
            };  
    
            _fooList = new List<Foo>
            {
                new Foo{EmailId = "one@bar.com", FirstName = "one", LastName = "bar", ProfileId = 28, IsDeleted = false}, 
                new Foo{EmailId = "two@bar.com", FirstName = "two", LastName = "bar", ProfileId = 29, IsDeleted = false},    
            }.AsQueryable();
            _mockSet = new Mock<DbSet<Foo>>();
            _mockSet.As<IQueryable<Foo>>().Setup(m => m.Provider).Returns(_fooList.Provider);
            _mockSet.As<IQueryable<Foo>>().Setup(m => m.Expression).Returns(_fooList.Expression);
            _mockSet.As<IQueryable<Foo>>().Setup(m => m.ElementType).Returns(_fooList.ElementType);
            _mockSet.As<IQueryable<Foo>>().Setup(m=>m.GetEnumerator()).Returns(_fooList.GetEnumerator());
        }
    
        [TestMethod]
        public void Create_GivenEntity_ReturnsGuidId()
        {
            //Arrange
            var guidId = Guid.NewGuid().ToString("N");
            var dbContext = new Mock<MyDbContext>().Object;
    
            IGenericRepository<Foo> genericRepository = new Mock<GenericRepository<Foo>>(dbContext).Object;
    
            //Act
            _waitingQueue.Id = guidId;
            var actualId = genericRepository.Create(_foo);
    
            //Assert
            Assert.IsNotNull(actualId);
            Assert.AreEqual(actualId, guidId);
    
        }
    
        [TestMethod]
        public void GetById_GivenEntityId_ReturnsEntity()
        {
            //Arrange
            var id = Guid.NewGuid().ToString("N");
            _foo.Id = id;
    
            var mockContext = new Mock<MyDbContext>();
            mockContext.Setup(c => c.Foo).Returns(_mockSet.Object);
            IGenericRepository<Foo> genericRepository = new Mock<GenericRepository<Foo>>(mockContext.Object).Object;
    
            //Act
            var fooId = genericRepository.Create(_foo);
            var fooObject = genericRepository.GetById(id);
    
            //Assert
            fooObject.PropertiesShouldEqual(_foo);
        }
    }
    

    这里是DbContext

    public class MyDbContext : DbContext
    {
        public MyDbContext() : base("fakeConnectionString")
        {
        }
    
        public virtual DbSet<Foo> WaitingQueues { get; set; }
    }
    

    我是新来的单元测试,我不知道我采取的方法是否正确。

    目前,第一次测试 Create_GivenEntity_ReturnsGuidId GetById_GivenEntityId_ReturnsEntity 失败。

    我犯的错误是 GetFirst(Expression<Func<T, bool>> @where, params Expression<Func<T, object>>[] nav) 一般保存法

    这是因为 GetFiltered(params Expression<Func<T, object>>[] nav) 被召唤时 GetFirst 返回空值。

    是因为现在 T GenericRepository<T> ?

    我得到的错误是

    System.ArgumentNullException
    HResult=0x80004003
    Message=Value cannot be null.
    Parameter name: source
    

    当我调试时我可以看到 GetById(string id) 方法已传入正确的id

    1 回复  |  直到 7 年前
        1
  •  1
  •   Zysce myrtle303    7 年前

    您没有设置DbContext.Set(),因此,由于Mock在默认情况下是松散行为,所以它应该返回null。

    // should be Mock<DbSet<Foo>>
    private Mock<DbSet<WaitingQueue>> _mockSet;
    // what it MyDbContext ? should not it be DbContext ? has it is in 
    // GenericRepository
    var mockContext = new Mock<MyDbContext>();
    // what is the point of this line ?
    mockContext.Setup(c => c.WaitingQueues).Returns(_mockSet.Object);
    // how to setup
    mockContext.Setup(c => c.Set<Foo>()).Returns(_mockSet.Object);
    

    nav始终为空,因为您只使用谓词调用GetFirst。

    public T GetById(string id)
    {
         // nav is null
         return GetFirst(x => x.Id == id);
    }      
    

    另外,如果要测试类GenericRepository,不要在测试中模拟它,否则,对它进行单元测试有什么意义?

    您要测试的是后面的逻辑,并测试它是否能够处理所有输入。

    例如,对于GetById方法,当id为空时测试,id为空,id不引用现有实体和成功的测试(找到实体)。