我已经实现了一个抽象的通用存储库,它定义了一组用于执行 CRUD 操作的方法。我正在尝试借助派生类中的工作单元模式来测试它们。我使用 Moq 作为测试框架并使用 MockQueryable 来启用 FirstOrDefaultAsync、AddAsync、SaveChangesAsync 等异步操作。我在测试 Add 方法时遇到错误。这是我创建的一个虚拟项目,用于展示如何设置。
DbContext 类
public class MyDBContextClass : DbContext, IDbContext
{
public MyDBContextClass(DbContextOptions options) : base(options) { }
public DbSet<Students> Students { get; set; }
}
抽象类
public abstract class MyGenericRepository<TEntity> where TEntity : class
{
private readonly IDbContext context;
public MyMyGenericRepository(IDbContext context){
this.context = context;
}
public virtual async Task<int> Add(TEntity Entity)
{
await context.Set<TEntity>().AddAsync(entity); // throws a NullReferenceException during test
await context.SaveChangesAsync();
}
}
工作单位
public class StudentUnitOfWork : MyGenericRepository<Student>
{
public class StudentUnitOfWork(IDBContext context) : base(context)
{
}
}
测试类
public class StudentUnitOfWorkTest
{
[Fact]
public async Task Add()
{
var students = new List<Student>
{
new Student{ Id = 1, Name = "John Doe"},
new Student{ Id = 2, Name = "Jane Doe"}
}
var mockSet = students.AsQueryable().BuildMockDbSet();
var mockContext = new Mock<IDbContext>();
mockContext.Setup(_ => _.Students).Returns(mockSet.Object);
var sut = new StudentUnitOfWork(mockContext.Object);
var newStudentObj = new Student
{
Name = "Justin Doe"
}
await sut.Add(newStudentObj); // throws a NullReferenceException
mockSet.Verify(_ => _.AddAsync(It.IsAny<Student>(), It.IsAny<CancellationToken>()), Times.Once());
mockContext.Verify(_ => _.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once());
}
}
覆盖和注入基本的 Add 方法也失败了
public override async Task Add(Student student)
{
await base.Add(category); // Still throws a NullReferenceException
}
当我在工作单元类中覆盖 Add 的实现并在这种情况下设置实际的 dbSet 时,测试通过了 Student。
public class StudentUnitOfWork : MyGenericRepository<Student>
{
public override async Task Add(Student student)
{
await context.Students.AddAsync(student); // Works
await context.SaveChangesAsync();
}
}
我是否遗漏了任何东西或 DbContext.Set 仅适用于生产而不是测试。