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

单元测试通用方法(NUnit)

  •  1
  • Ben_jamin  · 技术社区  · 7 年前

    我一直在尝试使用泛型类在.NETCore中实现存储库模式。这就是我想到的(我拿出了所有的方法,但只有一个保持简单)。类/方法可以工作,但我正在尝试为它编写一个单元(集成)测试,在本例中是Add方法。

    public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        protected readonly DbContext Context;
    
        public Repository(DbContext context)
        {
            Context = context;
        }
    
         public void Add(TEntity entity)
        {
            Context.Set<TEntity>().Add(entity);
        }
    }
    

    到目前为止,我的集成测试如下:, 设置生成要保存到的SqlLite数据库

    然后我创建一个“StorageSystem”域对象并测试泛型类。但我觉得我应该能够测试它,而不需要通过一个特定的领域模型。或者至少,输入不同的域模型作为参数化测试。

    [TestFixture]
    public class RepositoryTests
    {
        SqliteConnection _connection;
        DbContextOptions<ApplicationDbContext> _options;
        ApplicationDbContext _context;
        UnitOfWork _uow;
    
        [SetUp]
        public void SetUp()
        {
            _connection = new SqliteConnection("DataSource=:memory:");
            _connection.Open();
    
            _options = new DbContextOptionsBuilder<ApplicationDbContext>()
                .UseSqlite(_connection)
                .Options;
    
            using (var context = new ApplicationDbContext(_options))
            {
                context.Database.EnsureCreated();
            }
    
            _context = new ApplicationDbContext(_options);
            _uow = new UnitOfWork(_context);
        }
    
        [TearDown]
        public void TearDown()
        {
            _connection.Close();
        }
    
        [Test]
        public void Add_AddsEntityToRepository()
        {
            //arrange
            var storageSystem = new StorageSystem {Id = 1, Name = "Storage1"};
            var repo = new Repository<StorageSystem>(_context);
    
            //act
            repo.Add(storageSystem);
            _uow.Complete();
    
            //assert
            Assert.AreEqual(1, _context.StorageSystems.Count());
        }
    

    我对使用泛型相当陌生,我能找到的最接近的解决方案是使用抽象类。但是,我不能让它与我的代码一起工作,因为它不能将测试检测为抽象类,也不能生成TEntity类型的存储库。

    Example taken from here

    [TestFixture]
    public abstract class RepositoryTests1<TEntity>
    {
        SqliteConnection _connection;
        DbContextOptions<ApplicationDbContext> _options;
        ApplicationDbContext _context;
        UnitOfWork _uow;
    
        [SetUp]
        public void SetUp()
        {
            _connection = new SqliteConnection("DataSource=:memory:");
            _connection.Open();
    
            _options = new DbContextOptionsBuilder<ApplicationDbContext>()
                .UseSqlite(_connection)
                .Options;
    
            using (var context = new ApplicationDbContext(_options))
            {
                context.Database.EnsureCreated();
            }
    
            _context = new ApplicationDbContext(_options);
    
            _uow = new UnitOfWork(_context);
        }
    
        [TearDown]
        public void TearDown()
        {
            _connection.Close();
        }
    
    [Test]
    public void Add_AddsEntityToRepository_GenericAttempt()
        {
            //arrange
            TEntity entityToAdd = this.CreateEntity();
    
            var repo = new Repository<TEntity>(_context); //ERROR HERE - TEntity must be a reference type
    
            //act
            repo.Add(entityToAdd);
            _uow.Complete();
    
            //assert
            //NO IDEA WHAT THE ASSERTION WOULD BE
        }
    
        protected abstract TEntity CreateEntity();
    }
    

    简而言之,如何对这个通用存储库进行单元测试?

    1 回复  |  直到 7 年前
        1
  •  1
  •   Manuel Fuchs    7 年前

    您可以将存储库限制为由您创建的某个基类,比如EntityBase(这应该是抽象的)

    public class EntityBase
    {
        public int Id { get; set; }
    }
    
    public class Repository<TEntity> : IRepository<TEntity> where TEntity : EntityBase
    {
        ...
    }
    

    [Test]
    public void Add_AddsEntityToRepository()
    {
        //arrange
        var storageSystem = new StorageSystem {Id = 1, Name = "Storage1"};
        var repo = new Repository<EntityBase>(_context);
    
        //act
        repo.Add(storageSystem);
        _uow.Complete();
    
        //assert
        Assert.AreEqual(1, _context.StorageSystems.Count());
    }
    

    由于您要通过inherinition确保每个类型至少都有EntityBase的成员,因此不必进一步测试实体类型的继承树(除非您对此有特定的用例)

    如果您需要知道基类上的某些方法,但实现依赖于子类,只需将该方法作为基类中的抽象成员并在子类中重写即可。

    public class EntityBase
    {
        public int Id { get; set; }
    
        // sample method that copies member values from other object to current instance
        public abstract void CopyProperties(EntityBase other);
    }
    
    public class Student : EntityBase
    {
       public int Id { get; set; }
    
       public override void CopyProperties(EntityBase other)
       {
          ...
       }
    }