Reputation: 515
In my application, I have the following 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")
{
}
}
Database resources are being managed by Unit of Work and Generic repository (based on 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);
}
}
The repository:
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;
}
}
My controllers use UoW in the following way:
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
}
This all works just fine. Now I want to do some Unit Testing. Trying to make a fake LibraryUsers DbSet
using Moq:
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
}
But tests actually fail on Generic Repository
's Get()
method (Value cannot be null). Debugging showed that issue occurs in the constructor:
public GenericRepository(LibraryContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>(); // dbSet is actually null
}
Is there any way to fix it?
Upvotes: 2
Views: 3383
Reputation: 247203
That's because no where in your FakeUnitOfWork
code do you setup the Set
method on the DbContext for your mocked DbSet. Add the following to your InitFakeDbContext
_mockContext.Setup(c => c.Set<LibraryUser>()).Returns(mockSet.Object);
When using Moq you want to setup the members that you will be using in your tests otherwise you will get an exception.
Upvotes: 3