Please can someone show me how to properly mock this repository class. Basically I want to just mock out it so that I can easily test my services layer. Am moq using c# moq in my test project. Where am mostly having problems is in the virtual interface pattern used in the Query, Filter, Include and OrderBy methods. How do I mock it so that it can return the properly RepositoryQuery that I injected into my Repository mock.
The code shown below is part of my database layer that communicates with the database, so I want to mock it out so that I can easily test my services layer without external dependence to worry about.
public sealed class RepositoryQuery<TEntity> : IRepositoryQuery<TEntity> where TEntity : BaseEntity
{
private readonly List<Expression<Func<TEntity, object>>> _includeProperties;
private readonly Repository<TEntity> _repository;
private readonly List<Expression<Func<TEntity, bool>>> _filters;
private Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> _orderByQuerable;
private int? _page;
private int? _pageSize;
public RepositoryQuery(Repository<TEntity> repository)
{
_repository = repository;
_includeProperties = new List<Expression<Func<TEntity, object>>>();
_filters = new List<Expression<Func<TEntity, bool>>>();
}
public RepositoryQuery<TEntity> Filter(Expression<Func<TEntity, bool>> filter)
{
_filters.Add(filter);
return this;
}
public RepositoryQuery<TEntity> OrderBy(Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy)
{
_orderByQuerable = orderBy;
return this;
}
public RepositoryQuery<TEntity> Include(Expression<Func<TEntity, object>> expression)
{
_includeProperties.Add(expression);
return this;
}
public IQueryable<TEntity> Get()
{
return _repository.Get(_filters, _orderByQuerable, _includeProperties, _page, _pageSize);
}
}
and this
public class Repository<TEntity> : IRepository<TEntity> where TEntity : BaseEntity
{
private readonly Guid _instanceId;
private readonly DbSet<TEntity> _dbSet;
private readonly IDbContext _context;
public Repository(IDbContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
_instanceId = Guid.NewGuid();
}
public virtual IRepositoryQuery<TEntity> Query()
{
var repositoryGetFluentHelper = new RepositoryQuery<TEntity>(this);
return repositoryGetFluentHelper;
}
internal IQueryable<TEntity> Get(
List<Expression<Func<TEntity, bool>>> filters = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
List<Expression<Func<TEntity, object>>> includeProperties = null,
int? page = null,
int? pageSize = null)
{
IQueryable<TEntity> query = _dbSet;
if (includeProperties != null)
{
includeProperties.ForEach(i => query = query.Include(i));
}
if (filters != null && filters.Any())
{
query = filters.Aggregate(query, (current, filter) => current.Where(filter));
}
query = orderBy != null ? orderBy(query) : query.OrderBy(a => a.Id);
if (page != null && pageSize != null)
{
query = query
.Skip((page.Value - 1)*pageSize.Value)
.Take(pageSize.Value);
}
return query;
}
}
Hopefully your components depend on the interfaces IRepositoryQuery<TEntity> and IRepository<TEntity> and not the concrete implementations RepositoryQuery<TEntity> and Repository<TEntity>. If that is the case, then you provide test doubles for the interfaces for unit test purposes with Moq like so
var mockQuery = new Mock<IRepositoryQuery<TEntity>>();
// perform any setup needed on mockQuery for the particular System Under Test
var mockRepository = new Mock<IRepository<TEntity>>();
// perform any setup needed on mockRepository for the particular System Under Test
// component that relies on query and repository
// that is the System Under Test i.e. the focus of the unit test
var systemUnderTest = new SystemUnderTest(mockRepository.Object, mockQuery.Object);
An observation; Looking at RepositoryQuery<TEntity>, I think the methods should return the interface IRepositoryQuery<TEntity> as opposed to the concrete implementation RepositoryQuery<TEntity>.
If IRepositoryQuery is the wrapper for IRepository, then - to test your service layer - you don't need to mock IRepository. Just mock IRepositoryQuery.
Assuming that I want to check that SomeService.DoSomething correctly processes the result it gets from IRepositoryQuery.Get:
var mock = new Mock<IRepositoryQuery<SomeClass>>();
mock.Setup(o => o.Get(/* test parameters */)).Returns(/* result */);
var myService = new SomeService(mock.Object);
Assert.That(myService.DoSomething(), Is.EqualTo(/* expected result*/));
Related
Im trying to create a generic repository ,here is my IGenericRepository:
public interface IGenericRepository<TEntity> where TEntity : class
{
Task<IEnumerable<TEntity>> FindByFilterAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] including);
Task<TEntity> GetByIdAsync(int id);
Task<bool> InsertAsync(TEntity obj);
}
here is the implementation of the respository:
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
private readonly IServiceScopeFactory scopeFactory;
public GenericRepository(IServiceScopeFactory scopeFactory) => this.scopeFactory = scopeFactory;
public async Task<IEnumerable<TEntity>> FindByFilterAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] including)
{
using (var scope = this.scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<CleanArchitectureContext>();
var x = db.Set<TEntity>().AsQueryable();
if (including != null)
{
including.ToList().ForEach(s =>
{
if (s != null)
{
x = x.Include(s);
}
});
}
return await x.Where(predicate).ToListAsync().ConfigureAwait(true);
}
}
public Task<TEntity> GetByIdAsync(int id)
{
throw new NotImplementedException();
}
public Task<bool> InsertAsync(TEntity obj)
{
throw new NotImplementedException();
}
}
now lets say i need to have an interface which is going to inherit from the IGeneric repository and store data in the db:
public interface IStorePayoutRepository:IGenericRepository<PayoutModel>
{
}
so far so good, the problem is if i want to have a class and inherit from IStorePayoutRepository,then i need to implement all the members inside that which is not what i want,because i need only the store one(save or insert into db),
public class PayoutRepository : IGenericRepository<PayoutEntity>
{
//Im forced to implement all the members inside generic interface
}
as you see its not very optimal to implement all the members everytime as they could be irrelevant to the usecase,whats the right way here?i appreciate your help
I have a service let's say Foo service class.
public class FooService : IFooService
{
private readonly IFooRepository _repository;
private readonly ISomeService _eventService;
public FooService(IFooRepository repository, ISomeService eventService)
{
_repository = repository;
_someService = someService;
}
public IReadOnlyCollection<Foo> GetFoos(bool isDeleted = true)
{
var foos= _repository.GetList(x => x.IsDeleted == isDeleted).ToList();
return !foos.Any() ? new List<Foo>(): foos;
}
}
Here is IFooRepository
public interface IFooRepository : IGenericRepository<Foo>
{
}
and here is IGenericRepository
public interface IGenericRepository<T> where T: BaseEntity
{
IReadOnlyCollection<T> GetList(Expression<Func<T, bool>> where, params Expression<Func<T, object>>[] nav);
}
In my test I want to verify that FooService's GetFoos method calls GetList method
This is what I tried
[TestClass]
public class FooServiceTest
{
private IQueryable<Foo> _foos;
private Mock<IFooRepository> _fooRepository;
private FooService _fooService;
private Mock<ISomeService> _someService;
[TestInitialize]
public void SetUp()
{
_foos = new List<Foo>
{
new Foo
{
EmailId = "a#a.com",
IsDeleted = false,
},
new Foo
{
EmailId = "a#a.com",
IsDeleted = true,
},
}.AsQueryable();
}
[TestMethod]
public void GetGetFoos_CallsGetList()
{
//Arrange
var foos= _foos.Where(x => x.IsDeleted).ToList();
_fooRepository = new Mock<IFooRepository>();
_fooRepository.Setup(m => m.GetList(x => x.IsDeleted)).Returns(foos);
_someServiceMock = new Mock<ISomeService>();
_fooService = new FooService(_fooRepository.Object, _someServiceMock.Object);
//Act
_fooService.GetFoos(true);
//Assert
_fooRepository.Verify(m=>m.GetList(x=>x.IsDeleted), Times.Once());
}
}
But I get argument null exception in following line
var foos= _repository.GetList(x => x.IsDeleted == isDeleted).ToList();
Any clue why this is happening even though I am saying Returns(foos) during setup.
Also how do I verify the interface method was called?
What is happening (most likely) is Moq can't match Expression<Func<T, bool>> when you do the .Setup().
So instead you can use IsAny<>() approach:
_fooRepository.Setup(m => m.GetList(It.IsAny<Expression<Func<Foo, bool>>>())).Returns(foos);
If you want to assert what expression is passed in, try
Expression<Func<Foo, bool>> capturedExpression = null;
_fooRepository.Setup(m => m.GetList(It.IsAny<Expression<Func<Foo, bool>>>()))
.Returns((Expression<Func<Foo, bool>> e ) => { capturedExpression = e; return foos; });
Assert.IsTrue(capturedExpression.Compile()(_foos[1]));
Assert.IsFalse(capturedExpression.Compile()(_foos[0]));
to verify the method was called you can also change the last it a bit more:
_fooRepository.Setup(m => m.GetList(It.IsAny<Expression<Func<Foo, bool>>>()))
.Returns((Expression<Func<Foo, bool>> e ) => { capturedExpression = e; return foos; })
.Verifiable();
then _fooRepository.Verify(m=>m.GetList(It.IsAny<Expression<Func<Foo, bool>>>()), Times.Once()); However, if it is not called, then capturedExpression is null (that technique is known as implicit assertion)
I have a working repository.
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly DbContext Context;
public Repository(DbContext context)
{
Context = context;
}
public TEntity Get(int id)
{
return Context.Set<TEntity>().Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return Context.Set<TEntity>().ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return Context.Set<TEntity>().Where(predicate);
}
public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
{
return Context.Set<TEntity>().SingleOrDefault(predicate);
}
public void Add(TEntity entity)
{
Context.Set<TEntity>().Add(entity);
}
public void Remove(TEntity entity)
{
Context.Set<TEntity>().Remove(entity);
}
}
As I read in coding repositories, that you don't add any class until you really need it. Now, I need to add Include. I found this one in this community Use Include() method in repository:
public static class IncludeExtension
{
public static IQueryable<TEntity> Include<TEntity>(this IDbSet<TEntity> dbSet,
params Expression<Func<TEntity, object>>[] includes)
where TEntity : class
{
IQueryable<TEntity> query = null;
foreach (var include in includes)
{
query = dbSet.Include(include);
}
return query ?? dbSet;
}
}
Then, I changed it to fit in my code (As I think) to be:
public IEnumerable<TEntity> Include(IDbSet<TEntity> dbSet,
params Expression<Func<TEntity, object>>[] includes)
{
IEnumerable<TEntity> query = null;
foreach (var include in includes)
{
query = dbSet.Include(include);
}
return query ?? dbSet;
}
With direct access to context, I am able to write:
Provinces = _cmsDbContext.Provinces.Include(c => c.District).Include(c => c.District.Country).ToList();
But, with repository, I can't write:
Provinces = Currentunitofwork.ProvinceRepository.Include(c => c.District).Include(c => c.District.Country).ToList();
I got error:
cannot convert lambda expression to type IDbSet<Province> because it is not a delegate type
What is the problem here, please.
I suspect that your code is passing in the lambda expression to the IDbSet parameter and can not convert it to that type.
I have not been able to test but it compiles, if the method is a member of the Repository class then try this.
public IEnumerable<TEntity> Include(params Expression<Func<TEntity, object>>[] includes)
{
IDbSet<TEntity> dbSet = Context.Set<TEntity>();
IEnumerable<TEntity> query = null;
foreach (var include in includes)
{
query = dbSet.Include(include);
}
return query ?? dbSet;
}
Again thanks to #Adam Carr.
This is the method code now:
public IQueryable<TEntity> Include(params Expression<Func<TEntity, object>>[] includeExpressions)
{
IDbSet<TEntity> dbSet = Context.Set<TEntity>();
IQueryable<TEntity> query = null;
foreach (var includeExpression in includeExpressions)
{
query = dbSet.Include(includeExpression);
}
return query ?? dbSet;
}
What I change is use Set as a method not a property. So, instead of:
IDbSet<TEntity> dbSet = Context.Set<TEntity>;
I used:
IDbSet<TEntity> dbSet = Context.Set<TEntity>();
Also, I used IQueryable instead of IEnumerable.
Method to unit test: GetUserInfo
Following is the class containing the method:
public class AccountService : IAccountService
{
IUnitOfWork _UnitOfWork;
public AccountService(IUnitOfWork unitOfWork)
{
_UnitOfWork = unitOfWork;
}
public UserInfo GetUserInfo(string userName, string password)
{
var userInfo = new UserInfo();
userInfo.UserType = UserType.Invalid;
// Statement of interest
var portalUser = _UnitOfWork.Repository<DvaPortalUser>().Query().Filter(t => t.Email == userName && t.Password == password).Get().FirstOrDefault();
//....Rest of the code is not included for clarity
}
}
The interface to mock IUnitOfWork:
public interface IUnitOfWork
{
void Dispose();
void Save();
void Dispose(bool disposing);
IRepository<T> Repository<T>() where T : class;
}
Repository Implementation:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
public virtual RepositoryQuery<TEntity> Query()
{
var repositoryGetFluentHelper = new RepositoryQuery<TEntity>(this);
return repositoryGetFluentHelper;
}
internal IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>> orderBy = null,
List<Expression<Func<TEntity, object>>>
includeProperties = null,
int? page = null,
int? pageSize = null)
{
IQueryable<TEntity> query = DbSet;
if (includeProperties != null)
includeProperties.ForEach(i => query.Include(i));
if (filter != null)
query = query.Where(filter);
if (orderBy != null)
query = orderBy(query);
if (page != null && pageSize != null)
query = query
.Skip((page.Value - 1)*pageSize.Value)
.Take(pageSize.Value);
return query.ToList();
}
}
RepositoryQuery Implementation:
public sealed class RepositoryQuery<TEntity> where TEntity : class
{
private readonly List<Expression<Func<TEntity, object>>> _includeProperties;
private readonly Repository<TEntity> _repository;
private Expression<Func<TEntity, bool>> _filter;
private Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>> _orderByQuerable;
private int? _page;
private int? _pageSize;
public RepositoryQuery(Repository<TEntity> repository)
{
_repository = repository;
_includeProperties = new List<Expression<Func<TEntity, object>>>();
}
public RepositoryQuery<TEntity> Filter(Expression<Func<TEntity, bool>> filter)
{
_filter = filter;
return this;
}
public IEnumerable<TEntity> Get()
{
return _repository.Get(
_filter,
_orderByQuerable, _includeProperties, _page, _pageSize);
}
}
Unit Test Method:
[TestMethod]
public void AccountService_GetUserInfo_SuccessfulLogin()
{
var _UnitOfWork = new Mock<IUnitOfWork>();
_AccountService = new AccountService(_UnitOfWork.Object);
_UnitOfWork.Setup(a => a.Repository<T>())).Returns(??); //How do I setup this statement?
_UnitOfWork.VerifyAll();
}
Question: How do I setup mock call for the statement _UnitOfWork.Repository()?
I dont know how your IRepository<T> is implemented, but i gues your Query method returns a IEnumerable<T> or a list.
internal interface IRepository<T>
{
IEnumerable<T> Query();
}
// your mock
_UnitOfWork.Setup(a => a.Repository<DvaPortalUser>())).Returns(() => new MyTestRepository());
1. Solution
Define a explicit implemtation of you repository.
// your implementation
public class MyTestRepository : IRepository<DvaPortalUser>
{
public IEnumerable<DvaPortalUser> Query()
{
// return some test users (mocks)
return new List<DvaPortalUser> {new DvaPortalUser(), new DvaPortalUser()};
}
}
2. Solution (thanks to Yuliam Chandra)
Define a mock instead of the implemtation
var repository = new Mock<IRepository<DvaPortalUser>>();
// return some test users (mocks)
repository.Setup(a => a.Query()).Returns(new[] { new DvaPortalUser() });
_UnitOfWork.Setup(a => a.Repository<DvaPortalUser>()).Returns(repository.Object);
What you choose depends on your solution.
I am trying to replace the joins and use include but I don't know how to do that:
IRepository<Call> callRepository =
ObjectFactory.GetInstance<IRepository<Call>>();
IRepository<Reason> reasonRepository =
ObjectFactory.GetInstance<IRepository<Reason>>();
IRepository<SimTask.Domain.Business.Entities.System.Company>
companyRepository = ObjectFactory.GetInstance<IRepository<SimTask.Domain.
Business.Entities.System.Company>>();
IQueryable<CallsListItem> x =
from call in callRepository.GetQuery()
join reason in reasonRepository.GetQuery() on call.ReasonId equals reason.Id
join company in companyRepository.GetQuery() on call.CompanyId equals company.CompanyId
where call.CompanyId == companyId &&
(!isClosed.HasValue || call.IsClosed.Equals(isClosed.Value))
select new CallsListItem()
{
CallId = call.Id,
Description = call.Description,
CloseDateTime = call.CloseDateTime,
IsClosed = call.IsClosed,
OpenDateTime = call.OpenDateTime,
PhoneNumber = call.PhoneNumber,
ReasonName = reason.Name,
CompanyName = company.CompanyName
};
IRepository is implemented by:
public class EFRepository<T> : IRepository<T> where T : class
{
ObjectContext _context;
IObjectSet<T> _objectSet;
private ObjectContext Context
{
get
{
if (_context == null)
{
_context = GetCurrentUnitOfWork<EFUnitOfWork>().Context;
}
return _context;
}
}
private IObjectSet<T> ObjectSet
{
get
{
if (_objectSet == null)
{
_objectSet = this.Context.CreateObjectSet<T>();
}
return _objectSet;
}
}
public TUnitOfWork GetCurrentUnitOfWork<TUnitOfWork>() where TUnitOfWork : IUnitOfWork
{
return (TUnitOfWork)UnitOfWork.Current;
}
public IQueryable<T> GetQuery()
{
return ObjectSet;
}
public IEnumerable<T> GetAll()
{
return GetQuery().ToList();
}
public IEnumerable<T> Find(Func<T,bool> where)
{
return this.ObjectSet.Where<T>(where);
}
public T Single(Func<T,bool> where)
{
return this.ObjectSet.Single<T>(where);
}
public T First(Func<T,bool> where)
{
return this.ObjectSet.First<T>(where);
}
public void Delete(T entity)
{
this.ObjectSet.DeleteObject(entity);
}
public void Add(T entity)
{
this.ObjectSet.AddObject(entity);
}
public void Attach(T entity)
{
this.ObjectSet.Attach(entity);
}
public void SaveChanges()
{
this.Context.SaveChanges();
}
}
Why is Include better then joins?
How can I do Include?
Include is eager loading and it fills navigation properties in real entities without need to project to non entity type - this cannot be achieved with joins. Also Include uses left outer joins whereas your query uses inner joins so you will not get entities which don't have related entity.
In EFv1 and EFv4 Include is a method of ObjectQuery. I wrote this answer using EFv4.1 which contains extension method for IQueryable<T> as well as Includes with lambda expression. You can try it - it is just another library you will link to your project and you can still use EFv4.
The reason to wrap Include in custom method is not introducing dependency to EF in upper layer. If you don't download EFv4.1 you can use this:
public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, params string[] includes)
where T : class
{
if (includes != null)
{
var objectQuery = query as ObjectQuery;
if (objectQuery == null)
{
throw new InvalidOperationException("...");
}
objectQuery = includes.Aggregate(objectQuery,
(current, include) => current.Include(include));
}
return objectQuery;
}
The big disadvantage in both approaches (EFv4 and EFv4.1) is casting to ObjectQuery (EFv4.1 do it internally) - this can be serious issue in unit tests where you don't work with real queries.