在我的应用程序中,我有以下DbContext:
public class LibraryContext : DbContext
{
public virtual DbSet<LibraryUser> LibraryUsers { get; set; }
public virtual DbSet<BookCollection> BookCollections { get; set; }
public virtual DbSet<Book> LibraryBooks { get; set; }
public LibraryContext() : base("ExternalDB")
{
}
}
数据库资源由工作单元和通用存储库(基于ASP.NET's guidance)管理:
public class UnitOfWork : IUnitOfWork, IDisposable
{
private LibraryContext context = new LibraryContext();
private GenericRepository<BookCollection> collectionRepository;
private GenericRepository<LibraryUser> userRepository;
private GenericRepository<Book> bookRepository;
public GenericRepository<BookCollection> BookCollectionRepository
{
get
{
if (this.collectionRepository == null)
{
this.collectionRepository = new GenericRepository<BookCollection>(context);
}
return collectionRepository;
}
}
public GenericRepository<LibraryUser> LibraryUserRepository
{
get
{
if (this.userRepository == null)
{
this.userRepository = new GenericRepository<LibraryUser>(context);
}
return userRepository;
}
}
public GenericRepository<Book> BookRepository
{
get
{
if (this.bookRepository == null)
{
this.bookRepository = new GenericRepository<Book>(context);
}
return bookRepository;
}
}
public void Save()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
存储库:
public class GenericRepository<TEntity> where TEntity : class
{
internal LibraryContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(LibraryContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
{
query = query.Where(filter);
}
foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}
public virtual TEntity GetById(object id)
{
return dbSet.Find(id);
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}
public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}
public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}
我的控制器以下列方式使用UoW:
public class HomeController : Controller
{
IUnitOfWork uow;
public HomeController() : this (new UnitOfWork())
{
}
public HomeController(IUnitOfWork uow)
{
this.uow = uow;
}
public ActionResult Index()
{
if (Request.IsAuthenticated)
{
var books = uow.BookRepository.Get(filter:
b => b.UserId.HasValue, orderBy:
q => q.OrderBy(b => b.ReturnDate))
.Take(50);
//rest of the code
}
//rest of the code
}
//rest of the code
}
这一切都很好。现在我想做一些单元测试。尝试使用Moq伪造LibraryUsers DbSet
:
class FakeUnitOfWork : IUnitOfWork
{
Mock<LibraryContext> _mockContext;
public FakeUnitOfWork()
{
InitFakeDbContext();
}
public GenericRepository<LibraryUser> LibraryUserRepository
{
get
{
return new GenericRepository<LibraryUser>(_mockContext.Object);
}
}
public void Save()
{
throw new NotImplementedException();
}
public void InitFakeDbContext()
{
var data = FakeUsers.GetUsers(); // IQueryable<LibraryUser> data
var mockSet = new Mock<DbSet<LibraryUser>>();
mockSet.As<IQueryable<LibraryUser>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<LibraryUser>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<LibraryUser>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<LibraryUser>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
_mockContext = new Mock<LibraryContext>();
_mockContext.Setup(c => c.LibraryUsers).Returns(mockSet.Object);
}
// rest of the code
}
但是Generic Repository
Get()
方法的测试实际上失败了(Value不能为null)。调试显示问题出现在构造函数中:
public GenericRepository(LibraryContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>(); // dbSet is actually null
}
有没有办法解决它?
答案 0 :(得分:3)
那是因为你的FakeUnitOfWork
代码中没有在你的模拟DbSet的DbContext上设置Set
方法。将以下内容添加到InitFakeDbContext
_mockContext.Setup(c => c.Set<LibraryUser>()).Returns(mockSet.Object);
使用Moq时,您希望设置将在测试中使用的成员,否则您将获得例外。