单元测试通用方法 (NUnit)
Unit Testing Generic Methods (NUnit)
我一直在尝试使用通用 class 在 .Net Core 中实现存储库模式。这就是我想出的(为了保持简单,我只剩下一种方法)。 class / 方法有效,但我正在尝试为其编写单元(集成)测试,在本例中为 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 数据库保存到
设置 DbContext
设置一个工作单元 - 工作单元需要在 DbContext 中保存更改,大部分情况下可以忽略
然后我创建一个 "StorageSystem" 域对象并测试通用 class。但感觉我应该能够在不通过特定域模型的情况下对其进行测试。或者至少,输入不同的域模型作为参数化测试。
[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());
}
我对使用泛型还很陌生,我能找到的最接近的解决方案是使用抽象 class。但是我无法让它与我的代码一起工作,因为它没有将测试检测为抽象 class 并且无法创建 TEntity 类型的存储库。
[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();
}
简而言之,我如何对这个通用存储库进行单元测试?
您可以将您的存储库限制为您创建的某个基础 class,例如 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());
}
由于您通过继承确保每个类型都至少有 EntityBase 的成员,因此您不必在实体类型的继承树下进一步测试。 (除非你有一定的use-case)
如果你有某些方法,你需要知道base-type,但实现取决于child class,只需将方法作为抽象成员放在基类中class 并在 child class.
中覆盖它
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)
{
...
}
}
我一直在尝试使用通用 class 在 .Net Core 中实现存储库模式。这就是我想出的(为了保持简单,我只剩下一种方法)。 class / 方法有效,但我正在尝试为其编写单元(集成)测试,在本例中为 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 数据库保存到 设置 DbContext 设置一个工作单元 - 工作单元需要在 DbContext 中保存更改,大部分情况下可以忽略
然后我创建一个 "StorageSystem" 域对象并测试通用 class。但感觉我应该能够在不通过特定域模型的情况下对其进行测试。或者至少,输入不同的域模型作为参数化测试。
[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());
}
我对使用泛型还很陌生,我能找到的最接近的解决方案是使用抽象 class。但是我无法让它与我的代码一起工作,因为它没有将测试检测为抽象 class 并且无法创建 TEntity 类型的存储库。
[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();
}
简而言之,我如何对这个通用存储库进行单元测试?
您可以将您的存储库限制为您创建的某个基础 class,例如 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());
}
由于您通过继承确保每个类型都至少有 EntityBase 的成员,因此您不必在实体类型的继承树下进一步测试。 (除非你有一定的use-case)
如果你有某些方法,你需要知道base-type,但实现取决于child class,只需将方法作为抽象成员放在基类中class 并在 child class.
中覆盖它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)
{
...
}
}