I'm trying to moq a repository I have which is defined as:
public IQueryable<TEntity> GetAll(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null, bool disableTracking = true)
Is there a way to mock this? I want the query to execute, using the mock data i supply the repos. I'm not sure how to tell MOQ that when I call GetAll I want it to still run the query that is passed in, but do it aganist the dataset I supply. so it's not going to the db but against the mock set which I've configured. I'm able to create the data, it contain 12 records, but I want the getall moq call to execute it's query and filter it to just the 2 that should be returned.
The actual service where the call happens is:
var list = await _unitOfWork.GetRepository<CASE_ACTIVITY>().GetAll(predicate: x => x.SM_SITE_ID == siteId && x.CMS_USER_ID == userId
&& x.IS_DELETED == "N" && x.Appointment.IS_DELETED == "N" && x.Appointment.IS_ARCHIVED == "N" && x.IS_ARCHIVED == "N"
&& ((x.Appointment.APPOINTMENT_DATETIME.HasValue && x.Appointment.APPOINTMENT_DATETIME.Value.Date == DateTime.Today.Date)
|| (!x.Appointment.APPOINTMENT_DATETIME.HasValue && x.ACTIVITY_STATUS_ID == _appSettings.CASE_ACTIVITY_STATUS_ID_PENDING)))
.Include(x => x.Activity_Lookup).Include(x => x.Appointment).ThenInclude(x => x.Cms_Client).Include(x => x.Cms_Case)
.ToListAsync();
Assuming you have enough control over the GetRepository() method to make it return your mock repository, mocking the method itself is fairly straightforward (if a little verbose). I just dumped the GetAll method into an interface called IRepository, and this is what the mock looks like. Inside of the Returns method, you have access to each of the parameters to execute or ignore as you please.
var mock = new Moq.Mock<IRepository>();
mock.Setup(a => a.GetAll<int>(It.IsAny<Expression<Func<int, bool>>>(), It.IsAny<Func<IQueryable<int>, IOrderedQueryable<int>>>(), It.IsAny<Func<IQueryable<int>, IIncludableQueryable<int, object>>>(), It.IsAny<bool>()))
.Returns<Expression<Func<int, bool>>, Func<IQueryable<int>, IOrderedQueryable<int>>, Func<IQueryable<int>, IIncludableQueryable<int, object>>, bool>((param1, param2, param3, param4) =>
{
return new[] { 1, 2, 3 }.AsQueryable();
});
var result = mock.Object.GetAll<int>();
From here, we can't help much without seeing more code. In abstract terms, though, you'll take your mock.Object (which is of type IRepository) and feed it to whatever collection GetRepository() draws from. Also note, of course, that I used an int for the generic parameter -- you'll replace that with whatever type you're using. It may be possible to make a mock that accepts generic parameters, but that hopefully won't be necessary!
Related
I need one help to solve my mock related question in .net, I have one function with below code.
Task<ICollection<T>> GetAllAsync(Expression<Func<T, bool>> predicate, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, Func<IQueryable<T>, IQueryable<T>> includes = null);
Where we have a T as class, now I want to use the below code for the mocking.
var predict = PredicateBuilder.True<cls1>();
if (DropdownRequestVM?.AllParent == false)
{
predict = predict.And(x => x.Parentid == DropdownRequestVM.ParentID);
}
else
{
predict = predict.And(x => x.Parentid == null);
}
var returneddata = data.AsQueryable().Where(predict).ToList();
this.mockservice
.Setup(repo => repo.Repository
.GetAllAsync(It.IsAny<Expression<Func< cls1, bool>>>(),
It.IsAny<Func<IQueryable< cls1>, IOrderedQueryable< cls1>>>(),
It.IsAny<Func<IQueryable< cls1>, IQueryable< cls1>>>()))
.Returns(Task.FromResult<ICollection< cls1>>(returneddata));
Now my query is. I do not want to use the It.isany, as its allow all the expression, so that I have passed predict, but even I have setup the methods. Its returning the null. I have setup the method below way.
this.mockservice
.Setup(repo => repo.Repository
.GetAllAsync(predict,
It.IsAny<Func<IQueryable< cls1>, IOrderedQueryable< cls1>>>(),
It.IsAny<Func<IQueryable< cls1>, IQueryable< cls1>>>()))
.Returns(Task.FromResult<ICollection< cls1>>(returneddata));
You could try something like, not 100% sure about the syntax
this.mockservice
.Setup(repo => repo.Repository
.GetAllAsync(It.Is<Expression<Func<cls1,bool>>>(x => LambdaCompare.Eq(x,predict)),It.IsAny<Func<IQueryable<cls1>, IOrderedQueryable<cls1>>>(),It.IsAny<Func<IQueryable<cls1>, IQueryable<cls1>>>()))
.Returns(Task.FromResult<ICollection< cls1>>(returneddata));
I have a problem with Entity Framework using the DefaultIfEmpty method. The following query is returning empty when it should return an offer that matches all criteria in the database.
If I remove one or both DefaultIfEmpty method calls it works, but with them it doesn't. I need those to prevend another problem in the query.
When I execute the generated SQL query directly on the database it works and it returns the offer.
I also made an Unit Test reproducing the same example and it also passes so it must be an Entity Framework issue.
Here's the query:
private static Expression<Func<Offer, bool>> AddFilter(Service criteria)
{
return offer => offer.Restrictions.
SelectMany(rest => rest.OperatorRange.DefaultIfEmpty(), (rest, alop) => new { Restriction = rest, OperatorRange = alop.Id }).
Where(alop => criteria.ServiceUseNet == null || alop.OperatorRange.ToUpper() == criteria.ServiceUseNet.ToUpper()).
SelectMany(rest => rest.Restriction.CallType.DefaultIfEmpty(), (rest, till) => new { Restriction = rest, CallType = till.Id }).
Any(till => criteria.UseServiceCoverage == null || till.CallType.ToUpper() == criteria.UseServiceCoverage.ToUpper());
}
Change it into two Any calls:
return offer => offer.Restrictions
.Any(rest
=> rest.OperatorRange
.Where(alop => criteria.ServiceUseNet == null
|| alop.OperatorRange.ToUpper() == criteria.ServiceUseNet.ToUpper())
.Any(till => criteria.UseServiceCoverage == null
|| till.CallType.ToUpper() == criteria.UseServiceCoverage.ToUpper()));
The predicate is supposed to test whether there are any OperatorRanges (meeting some criteria) having any CallTypes meeting some criteria. If there are no OperatorRanges, there won't be any CallTypes either, let alone matching CallTypes.
In this form, the predicate always returns true or false.
Can someone explain to me why the EF Engine is failing in the following scenario?
It works fine with the following expression:
var data = context.Programs
.Select(d => new MyDataDto
{
ProgramId = d.ProgramId,
ProgramName = d.ProgramName,
ClientId = d.ClientId,
Protocols = d.Protocols.Where(p => p.UserProtocols.Any(u => u.UserId == userId))
.Count(pr => pr.Programs.Any(pg => pg.ProgramId == d.ProgramId))
})
.ToList();
But if I encapsulate some into an extension method:
public static IQueryable<Protocol> ForUser(this IQueryable<Protocol> protocols, int userId)
{
return protocols.Where(p => p.UserProtocols.Any(u => u.UserId == userId));
}
The resulting query:
var data = context.Programs
.Select(d => new MyDataDto
{
ProgramId = d.ProgramId,
ProgramName = d.ProgramName,
ClientId = d.ClientId,
Protocols = d.Protocols.ForUser(userId)
.Count(pr => pr.Programs.Any(pg => pg.ProgramId == d.ProgramId))
})
.ToList();
Fails with the exception: LINQ to Entities does not recognize the method 'System.Linq.IQueryable1[DAL.Protocol] ForUser(System.Linq.IQueryable1[DAL.Protocol], Int32)' method, and this method cannot be translated into a store expression.
I would expect the EF Engine to build the entire expression tree, chaining the necessary expressions and then generate the SQL. Why doesn't it do that?
This is happening because the call to ForUser() is being made inside of the expression tree that the C# compiler builds when it sees the lambda you pass into Select. Entity Framework tries to figure out how to convert that function into SQL, but it can't invoke the function for a few reasons (e.g. d.Protocols does not exist at the moment).
The simplest approach that works for a case like this is to have your helper return a criteria lambda expression, and then pass that into the .Where() method yourself:
public static Expression<Func<Protocol, true>> ProtocolIsForUser(int userId)
{
return p => p.UserProtocols.Any(u => u.UserId == userId);
}
...
var protocolCriteria = Helpers.ProtocolIsForUser(userId);
var data = context.Programs
.Select(d => new MyDataDto
{
ProgramId = d.ProgramId,
ProgramName = d.ProgramName,
ClientId = d.ClientId,
Protocols = d.Protocols.Count(protocolCriteria)
})
.ToList();
More information
When you invoke a LINQ method outside of an expression tree (like you do with context.Programs.Select(...)), the Queryable.Select() extension method actually gets invoked, and its implementation returns an IQueryable<> that represents the extension method getting called on the original IQueryable<>. Here's the implementation of Select, for instance:
public static IQueryable<TResult> Select<TSource,TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector) {
if (source == null)
throw Error.ArgumentNull("source");
if (selector == null)
throw Error.ArgumentNull("selector");
return source.Provider.CreateQuery<TResult>(
Expression.Call(
null,
GetMethodInfo(Queryable.Select, source, selector),
new Expression[] { source.Expression, Expression.Quote(selector) }
));
}
When the queryable's Provider has to generate actual data from the IQueryable<>, it analyzes the expression tree and tries to figure out how to interpret those method calls. Entity Framework has built-in knowledge of many LINQ-related functions like .Where() and .Select(), so it knows how to translate those method calls into SQL. However, it doesn't know what to do for methods that you write.
So why does this work?
var data = context.Programs.ForUser(userId);
The answer is that your ForUser method is not implemented like the Select method above: you are not adding an expression to the queryable to represent calling ForUser. Instead, you are returning the result of a .Where() call. From the IQueryable<>'s perspective, it's as if Where() was called directly, and the call to ForUser() never happened.
You can prove this by capturing the Expression property on the IQueryable<>:
Console.WriteLine(data.Expression.ToString());
... which will produce something like this:
Programs.Where(u => (u.UserId == value(Helpers<>c__DisplayClass1_0).userId))
There's no call to ForUser() anywhere in that expression.
On the other hand, if you include the ForUser() call inside of an expression tree like this:
var data = context.Programs.Select(d => d.Protocols.ForUser(id));
... then the .ForUser() method never actually gets invoked, so it never returns an IQueryable<> that knows the .Where() method got called. Instead, the expression tree for the queryable shows .ForUser() getting invoked. Outputting its expression tree would look something like this:
Programs.Select(d => d.Protocols.ForUser(value(Repository<>c__DisplayClass1_0).userId))
Entity Framework has no idea what ForUser() is supposed to do. As far as it's concerned, you could have written ForUser() to do something that's impossible to do in SQL. So it tells you that's not a supported method.
As I mentioned in my comment above, I can't tell why the EF Engine is working the way it is. Therefore, I've tried to find a way to re-write the query so I'll be able to make use of my extension methods.
The tables are:
Program -> 1..m -> ProgramProtocol -> m..1 -> Protocol
ProgramProtocol is just a join table and is not mapped in the model by Entity Framework.
The idea is simple: select "from left", select "from right" and then join the resulted sets for proper filtering:
var data = context.Programs.ForUser(userId)
.SelectMany(pm => pm.Protocols,
(pm, pt) => new {pm.ProgramId, pm.ProgramName, pm.ClientId, pt.ProtocolId})
.Join(context.Protocols.ForUser(userId), pm => pm.ProtocolId,
pt => pt.ProtocolId, (pm, pt) => pm)
.GroupBy(pm => new {pm.ProgramId, pm.ProgramName, pm.ClientId})
.Select(d => new MyDataDto
{
ProgramName = d.Key.ProgramName,
ProgramId = d.Key.ProgramId,
ClientId = d.Key.ClientId,
Protocols = d.Count()
})
.ToList();
I am attempting to test the following code:
public async Task<Activity> Get(long ID, Recruiter User, bool IsArchived = false)
{
Activity result = await collection.FirstOrDefault(x => x.ID == ID && x.Recruiter.CompanyID == User.CompanyID && (!x.Archived || IsArchived));
return result;
}
With the following test:
[TestMethod]
public async Task GetDoesThings()
{
long ID = 1;
bool IsArchived = false;
Recruiter User = new Recruiter()
{
CompanyID = 1
};
ActivitiesMock.Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived))).ReturnsAsync(new Activity());
Activity result = await repo.Get(ID, User);
ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)));
}
(I know there are different ways of writing it, this is the most recent iteration we've tried.)
The ActivitiesMock relates to the collection found in Get(long ID, Recruiter User, bool IsArchived = false). We recently wrote wrappers in order to try and test our Entity calls more efficiently, but we're running into this error when trying to verify the calls are made correctly:
Test method ExampleProject.Tests.Backend.Repositories.ActivityRepositoryTests.GetDoesThings threw exception:
Moq.MockException:
Expected invocation on the mock at least once, but was never performed: x => x.FirstOrDefault(y => (y.ID == .ID && y.Recruiter.CompanyID == .User.CompanyID) && (!(y.Archived) || .IsArchived))
Configured setups:
x => x.FirstOrDefault(y => (y.ID == .ID && y.Recruiter.CompanyID == .User.CompanyID) && (!(y.Archived) || .IsArchived)), Times.Never
Performed invocations:
IAppCollection`2.FirstOrDefault(x => (((x.ID == value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).ID) AndAlso (x.Recruiter.CompanyID == value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).User.CompanyID)) AndAlso (Not(x.Archived) OrElse value(ExampleProject.Backend.Repositories.ActivityRepository+<>c__DisplayClass2_0).IsArchived)))
In this instance the wrapper (collection) is a mock of the interface. The goal is to ensure that the repository is calling the correct expression on the wrapper, so that we know the predicate that's being passed to the Entity DbSet is correct without having to worry about all the messy async abstractions.
The Mock Setup() with the full predicate doesn't appear to be found when the test is ran, and when I change the Setup() to It.IsAny<Expression<Func<Activity, bool>>>() it runs the mock and provides the return, but the Verify call doesn't work. So, running:
ActivitiesMock.Setup(x => x.FirstOrDefault(It.IsAny<Expression<Func<Activity, bool>>>())).ReturnsAsync(new Activity());
Activity result = await repo.Get(ID, User);
Assert.IsNotNull(result);
ActivitiesMock.Verify(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)));
Passes the assert but fails the Verify, whereas running:
ActivitiesMock
.Setup(x => x.FirstOrDefault(y => y.ID == ID && y.Recruiter.CompanyID == User.CompanyID && (!y.Archived || IsArchived)))
.ReturnsAsync(new Activity())
.Verifiable();
Activity result = await repo.Get(ID, User);
Assert.IsNotNull(result);
ActivitiesMock.Verify();
Fails on the assert.
It looks like it's failing because it's expecting the same object types. Am I trying to do something that Moq can't handle, or am I missing something that I need to do in order to get the verification to be correct?
By request, the concrete implementation of the LINQ-to-Entity wrapper (collection) is:
public Task<T> FirstOrDefault(Expression<Func<T, bool>> Predicate)
{
return DbSet.FirstOrDefaultAsync(Predicate);
}
Though the wrapper itself isn't being used, but an interface for it is being mocked, and it's that mock that we're testing.
The answer is neither. Since the anonymous functions have to create class instances to store the data being provided, they create DisplayClass instances to hold the data. Since those instances are being created in different namespaces (among other things) they don't pass when Moq calls .Equals against them.
We solved this problem by writing our tests as such:
ActivitiesMock
.Setup(x => x.Where(It.IsAny<Expression<Func<Activity, bool>>>()))
.Returns((Expression<Func<Activity, bool>> x) =>
{
actualPredicate = x;
return queryMock.Object;
});
Then creating valid and invalid activities to provide to the predicate to ensure it returns true or false correctly:
Assert.IsTrue(actualPredicate.Compile().Invoke(validActivity));
Granted for now it's a bit hacky, but at first glance it doesn't seem too much like a dumpster fire solution, and it's a way for us to ensure the calls being provided do what we expect them to, which is what we want.
Update (Sep 7th, 2016): So far this has been working well for us. We've ran into an issue where LINQ-to-Entity statements don't run as expected because the LINQ is case-sensitive and the SQL generated isn't, but since that isn't a deal breaker for us we're just fine.
I have a method in my project that repeats over and over:
public PAC PAC_GetByCodiPac(string codiPac)
{
var sel = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac);
if (sel.Count() > 0)
return sel.First();
return null;
}
The table PAC means (patient), so I have these methods for all the tables I have.
How can I make a generic method for this?
Thanks in advance.
Here is your generic method. Note, that as others pointed out FirstOrDefault is better than count and then first, so I'm using it here. But it's also possible to write the expression so that it mimics what your original code does. Please let me know if you need additional help with this.
public static T GetByCodi<T>(IQueryable<T> table, string codi, string fieldName) where T : class
{
// x
ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
Expression currentExpression = parameter;
Type currentType = typeof(T);
PropertyInfo property = currentType.GetProperty(fieldName);
// x.CODI_xxx
currentExpression = Expression.Property(currentExpression, property);
// x.CODI_xxx == codi
currentExpression = Expression.Equal(currentExpression, Expression.Constant(codi));
// x => x.CODI_xxx == codi
LambdaExpression lambdaExpression = Expression.Lambda(currentExpression, parameter);
return table.FirstOrDefault((Func<T, bool>)lambdaExpression.Compile());
}
You use it like this:
PAC xxx = GetByCodi<PAC>(_gam.PAC, codiPac, "CODI_PAC");
Edit 1:
I changed the code according to the comment so that you can pass arbitrary ID field name in.
I see that what you asked is a very straight forward where query even doesn't require to have have it on a separate method.
Also you can simply enhance your query link the following:
public PAC PAC_GetByCodiPac(string codiPac)
{
return _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);
}
FirstOrDefault will return the first item on the array, if not it will return null.
If you want a generic method that lets you specify any table and any predicate for records from that table then you can't really get any better than the built-in Where<T>(...) and (as others have already pointed out) the FirstOrDefault<T>(...) extension methods.
Your code would then look like so:
var result = _gam.PAC.Where(pac => pac.CODI_PAC == codiPac).FirstOrDefault();
// OR
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);
The best you could get then, writing your own generic method, would be this:
public T FirstOrDefault<T>(IQueryable<T> source,
Expression<Func<T, bool>> predicate)
{
return source.Where(predicate).FirstOrDefault();
// OR
// return source.FirstOrDefault(predicate);
}
And that is really just redundant. Especially when your calling code would be actually longer using the helper method:
var result = FirstOrDefault(_gam.PAC, pac => pac.CODI_PAC == codiPac);
// versus
var result = _gam.PAC.FirstOrDefault(pac => pac.CODI_PAC == codiPac);
And even worse, your code is no longer using a fluent, composable syntax. This just makes readability and maintenance more difficult.
If you stick with using the IQueryable<T> extension methods then you can do composition like this:
var result = _gam.PAC
.Where(pac => pac.CODI_PAC == codiPac)
.Where(pac => pac.SomeOtherProperty == someOtherValue)
.FirstOrDefault();
// OR
var result = (from pac in _gam.PAC
where pac.CODI_PAC == codiPac
where pac.SomeOtherProperty == someOtherValue
select pac).FirstOrDefault();
One very important thing to note here is that the predicate parameter in the IQueryable<T>.Where<T>(...) extension method is of type Expression<Func<T, bool>>. This allows the IQueryable<T> provider to construct the native SQL (or other native provider query) at the very last moment before returning a result.
Not using Expression<Func<T, bool>> means that your query would be the equivalent of this:
var result =
_gam.PAC
.ToArray()
.Where(pac => pac.CODI_PAC == codiPac)
.FirstOrDefault();
And that would mean the query will load every record from the "PAC" table into memory before selecting the first filtered result and throwing out the rest of the results.
The bottom-line is that by making a generic helper method you are rewriting existing framework code and you open yourself to performance and maintenance issues while also reducing code readability.
I hope this helps.
I'm not sure if you are asking for this, but this method could be in a static class and method and so you'd be able to call it from everywhere.
An easy solution will be:
//a generic method
private PAC PAC_GetPAC(Func<PAC, bool> predicate)
{
return _gam.PAC.Where(predicate).FirstOrDefault();
}
public PAC PAC_GetPACById(long id)
{
return PAC_GetPAC(p => p.ID == id);
}
public PAC PAC_GetByCodiPac(string codiPac)
{
return PAC_GetPAC(p => pac.CODI_PAC == codiPac);
}