Unit testing using Moq and setting up GetAll with include - c#

I have this strange problem with MOQ and I cant use the GetAll('include') method to test my controller.
My Tests initialization
// GetAll
menusDb.Setup(m => m.GetAll()).Returns(menus.AsQueryable());
menusDb.Setup(m => m.GetAll(It.IsAny<Expression<Func<Menu, object>>>()))
.Returns((Expression<Func<Menu,object>> pred) => {
return menus.AsQueryable();
});
// FindByIdAsync
menusDb.Setup(m => m.FindByByIdAsync(It.IsAny<int>()))
.Returns((int x) => Task.FromResult(menus.Find(m => m.ID == x)));
menusDb.Setup(m => m.FindByByIdAsync(It.IsAny<int>(), It.IsAny<Expression<Func<Menu, object>>[]>()))
.Returns((int x, Expression<Func<Menu,
object>>[] includeProperties) => Task.FromResult(menus.Find(m => m.ID == x)));
Now whenever I am trying to test
_menusDB.GetAll(s=>s.Sections)
The moq version of menusdb.getAll() method is not fired at all
All other Moq methods are triggered correctly...
examples
_menusDB.GetAll();
_menusDB.FindByByIdAsync(id,
m => m.Sections.Select(s => s.Image),
m => m.Sections.Select(s => s.MenuItems.Select(mi => mi.Image)));
And these are the Getall and find functions with includes in my generic repository.
public IQueryable<TEntity> GetAll<TProperty>(Expression<Func<TEntity, TProperty>> propertyToInclude) {
return ObjectSet.Include(propertyToInclude);
}
public async Task<TEntity> FindByByIdAsync(int id, params Expression<Func<TEntity, object>>[] propertiesToInclude) {
var query = propertiesToInclude.Aggregate(ObjectSet as IQueryable<TEntity>, (current, property) => current.Include(property));
return await query.SingleOrDefaultAsync(entity => entity.ID == id).ConfigureAwait(false);
}

I finally found where is the problem. GetAll with include uses generic TProperty instead of object to include the properties. Mock cant somehow relate the object Tproperty with the linq query i provide in test. Maybe there is a way to make it work but for now i simply changed the generic property to object

Related

How do I mock an AbstractValidator that is using rule sets?

I have an abstract validator, with the following structure:
public abstract class RiskAssessmentServiceCreateRequestValidator<T>
: AbstractValidator<T> where T
: IRiskAssessmentServiceCreateRequest
{
public RiskAssessmentServiceCreateRequestValidator(ApplicationContext context)
{
RuleSet("modelBinding", () =>
{
RuleFor(x => x.ServiceProviderId).NotNull().GreaterThan(0);
});
RuleSet("handler", () =>
{
//....
});
}
}
In my request handler I am calling a derived instance of this class like that:
var validationResult = _validator.Validate(request, ruleSet: "handler");
How can I mock that particular call to Validate in my unit tests? If I would not use the rule sets, my Setup would look like this:
_validator.Setup(x => x.Validate(It.IsAny<CreateRequest>()))
.Returns(validationResult);
The following call is not allowed, since optional parameters are not allowed in an expression tree:
_validator.Setup(x => x.Validate(
It.IsAny<CreateRequest>(),
ruleSet: It.IsAny<string>()))
.Returns(validationResult);
Theoretically I could set it up like this:
_validator.Setup(x => x.Validate(
It.IsAny<CreateRequest>(),
(IValidatorSelector)null,
It.IsAny<string>()))
.Returns(validationResult);
But this then results in:
System.NotSupportedException : Unsupported expression: x => x.Validate<CreateRequest>(It.IsAny<CreateRequest>(), null, It.IsAny<string>())
Extension methods (here: DefaultValidatorExtensions.Validate) may not be used in setup / verification expressions.
Except from using the real validator, which I want to avoid, how can I resolve this and setup Moq in a suitable way?
There are really two questions here.
The first is how to mock with optional parameters - Simply treat optional parameters are non-optional.
However, you are trying to mock an extension method, that is not possible. Instead, you need to mock the method that the extension is trying to call. A cursory glance at the source, and I think that under the hood it is calling validator.Validate(ValidationContext) so your Moq code could be something like this:
_validator
.Setup(x => x.Validate(It.IsAny<ValidationContext<CreateRequest>>())
.Returns(validationResult);
Try
var mock = new Mock<AbstractValidator<object>>();
mock.Setup(x => x.Validate(It.Is<ValidationContext<object>>(ctx => IsExpectedRuleSet(ctx, new[] { "Rule1", "Rule2" }))))
.Return(...);
mock.Object.Validate(new object(), ruleSet: "Rule1,Rule2");
bool IsExpectedRuleSet(ValidationContext context, string[] expectedRuleSet)
{
return (context.Selector as FluentValidation.Internal.RulesetValidatorSelector)?.RuleSets.SequenceEqual(expectedRuleSet) == true;
}

Mock Expression Parameter to Repository Method

Using Moq. I have a repository with the following interface:
public virtual IEnumerable<TEntity> GetBySpec(ISpecification<TEntity> specification, params string[] includes)
{
IQueryable<TEntity> query = includes.Aggregate<string, IQueryable<TEntity>>(_dbSetQuery, (current, include) => current.Include(include));
return query.Where(specification.SatisfiedBy())
.AsEnumerable<TEntity>();
}
In this case, i'm using a DirectSpecification:
public sealed class DirectSpecification<TEntity> : Specification<TEntity>
{
Expression<Func<TEntity, bool>> _MatchingCriteria;
public DirectSpecification(Expression<Func<TEntity, bool>> matchingCriteria)
{
_MatchingCriteria = matchingCriteria;
}
public override Expression<Func<TEntity, bool>> SatisfiedBy()
{
return _MatchingCriteria;
}
}
In my actual code i'm calling
var recentlyChanged = _vwPersonRepository.GetBySpec(
new DirectSpecification<vwPerson>(person =>
person.ModifiedDate > modifiedFromDay &&
person.ModifiedDate < modifiedTo));
var recentlyCreated = _vwPersonRepository.GetBySpec(
new DirectSpecification<vwPerson>(person =>
person.CreatedDate > createdFromDay &&
person.CreatedDate < createdTo));
Edit: As suggested by duplicate, I've tried this:
Container.GetMock<IvwPersonRepository>()
.Setup(p => p.GetBySpec(It.IsAny<ISpecification<vwPerson>>()))
.Returns((Expression<Func<vwPerson, bool>> predicate) =>
items.Where(predicate));
I get a
Exception thrown: 'System.Reflection.TargetParameterCountException' in mscorlib.dll
Additional information: Parameter count mismatch.
My question is complicated by having the ISpecification parameter, how can I get the correct parameters so I can work with the predicate?
Edit 2: Thanks to Patrick, here is the solution:
Container.GetMock<IvwPersonRepository>()
.Setup(p => p.GetBySpec(It.IsAny<ISpecification<vwPerson>>(), It.IsAny<string[]>()))
.Returns((ISpecification<vwPerson> specification, string[] includes) =>
items.Where(predicate));
They key was to include the string[] includes, even though I don't pass it as a parameter the reflection finds it and expects it to be there.
Brilliant!
The Setup call in your edit is wrong, it should be:
Container.GetMock<IvwPersonRepository>()
.Setup(p => p.GetBySpec(It.IsAny<ISpecification<vwPerson>>()))
.Returns((ISpecification<vwPerson> specification) => /* TODO */);
(This is because the parameters passed to Returns are the parameters passed to the function being setup, which in this case is GetBySpec.)
I believe (based on what you posted) you could just do this:
Container.GetMock<IvwPersonRepository>()
.Setup(p => p.GetBySpec(It.IsAny<ISpecification<vwPerson>>()))
.Returns((ISpecification<vwPerson> specification) => items.Where(specification.SatisfiedBy()));
However, you might see some benefit by using a factory to create your specifications so that you can mock them to avoid relying on their implementation (in the call to SatisfiedBy above).

Return passed parameter with fluent moq

Is it possible to return passed parameter to mocked method with fluent moq?
From:
mock.Setup(m => m.Foo(
It.IsAny<string>())).Returns<string>(s => s);
to:
Mock.Of<Bar>(m => m.Foo(It.IsAny<string>()) == ???);

Using MOQ to verify expression parameter

I am trying to verify the method i am tested has been invoked with a particular expression. I have spent hours on this without the result i wanted.
This is the System under test
public class sut
{
private IEntityUtil _ew;
public sut(IEntityUtil ew)
{
_ew = ew;
}
public void Search()
{
Guid id = Guid.Parse("CB594050-3845-4EAF-ABC5-34840063E94F");
var res = _ew.SelectSingle<Post>(w => w.Id == id, new PersonalSiteEntities());
}
}
This is the dependency
public interface IEntityUtil
{
TEntity SelectSingle<TEntity>(Expression<Func<TEntity, bool>> predicate, System.Data.Objects.ObjectContext ctx)
where TEntity : EntityObject;
List<TEntity> SelectList<TEntity>(Expression<Func<TEntity, bool>> predicate, System.Data.Objects.ObjectContext ctx)
where TEntity : EntityObject;
bool Insert<TEntity>(TEntity entity, System.Data.Objects.ObjectContext ctx)
where TEntity : EntityObject;
}
And this is how i am trying to test it
public class tst
{
[TestMethod]
public void tst1()
{
var cwMock = new Mock<ConsoleApplication1.IEntityUtil>();
Guid id = Guid.Parse("CB594050-3845-4EAF-ABC5-34840063E94F");
//cwMock.Setup(x => x.SelectSingle<ConsoleApplication1.Post>(w => w.Id == id, It.IsAny<System.Data.Objects.ObjectContext>())).Returns(new ConsoleApplication1.Post()).Verifiable();
//cwMock.Setup(x => x.SelectSingle(It.IsAny<Expression<Func<ConsoleApplication1.Post, bool>>>(), It.IsAny<System.Data.Objects.ObjectContext>())).Returns(new ConsoleApplication1.Post()).Verifiable();
Expression<Func<ConsoleApplication1.Post, bool>> func = (param) => param.Id == id;
cwMock.Setup(x => x.SelectSingle<ConsoleApplication1.Post>(func, It.IsAny<System.Data.Objects.ObjectContext>())).Returns(new ConsoleApplication1.Post());
var sut = new ConsoleApplication1.sut(cwMock.Object);
sut.Search();
//cwMock.VerifyAll();
cwMock.Verify(x => x.SelectSingle(func, It.IsAny<System.Data.Objects.ObjectContext>()));
}
}
Please note the second commented setup will make the test pass but it wont let me verify that a specific expression has been passed in.
Thanks in advance.
Two things that will greatly help (us help you) are
Give your test a meaningful name so we know what you're after,
Arrange your test into three areas, and separate by comments or whitespace:
Arrange,
Act,
Assert
This makes it a bit more clear what the action is.
That said, it appears to me that you are trying to assert that ew.SelectSingle was called once when calling sut.Search()?
Also I noticed you're creating the Guid in your test but never doing anything with it. So, here is a quick proposal on your test (not using the IDE so you may find errors):
[Fact]
public void Verify_SelectSingle_IsCalledOnce( ){
Guid id = Guid.Parse( "CB594050-3845-4EAF-ABC5-34840063E94F" );
var cwMock = new Mock<ConsoleApplication1.IEntityUtil>( );
var post = new ConsoleApplication1.Post{ Id = id };
cwMock
.Setup( x=> x.SelectSingle<ConsoleApplication1.Post>(It.IsAny<Guid> ))
.Returns( post );
var sut = new ConsoleApplication1.sut(cwMock.Object);
sut.Search();
cwMock.Verify(
x=> x.SelectSingle( It.IsAny<ObjectContect>( o => o.Id == id )),
Times.Once);
}
As already noted, it's very hard to tell exactly what you're trying to accomplish because you haven't made your test names explicit. That said, it looks like you need to provide a callback to your mocked setup that will allow you to verify the expression. Something like this should help you (using the commented out setup that passes):
cwMock.Setup(x => x.SelectSingle(It.IsAny<Expression<Func<ConsoleApplication1.Post, bool>>>(), It.IsAny<System.Data.Objects.ObjectContext>())).Callback<Expression<Func<ConsoleApplication1.Post, bool>>>(VerifyExpression).Returns(new ConsoleApplication1.Post()).Verifiable();
Then create a callback method
private static void VerifyExpression(Expression<Func<ConsoleApplication1.Post, bool>> expression)
{
var func = expression.Compile();
// call func(params) and verify against it
}

Using Moq for a repository interface method?

I have the following method on my repository interface:
IQueryable<T> GetQuery<T>(Expression<Func<T, bool>> predicate) where T : class;
I have a class I'm going to act on in a unit test with the following constructor:
public MyClass(IUnitOfWork unitOfWork)
On IUnitOfWork Interface there is an exposed Repository property:
Repository Repository { get; }
So I'm trying to unit test the MyClass.DoSomething() method like so:
[TestInitialize]
public void Setup()
{
accounts = new List<Account>()
{
new Account()
{
Id = 123
}
};
}
Next I have the unit test Arrange section which is failing:
//Arrange
var repositoryMock = new Mock<IUnitOfWork>();
repositoryMock.Setup(x => x.Repository.GetQuery<Account>(y => y.Id == 123))
.Returns(accounts.AsQueryable()); //This setup always fails
var myClass = new MyClass(repositoryMock.Object); //don't even get here
The exception I get is:
System.NotSupportedException: Invalid setup on a non-virtual
(overridable in VB) member: x => x.Repository.GetQuery(y =>
y.Id == 123)
I've tried other variations of the Setup on the mock:
repositoryMock.Setup(x => x.Repository.GetQuery<Account>()).Returns((Account a) => accounts.AsQueryable().Where(z => z.Id == 123));
and
repositoryMock.Setup(x => x.Repository.GetQuery<Account>(y => y.Id == 123)).Returns((Account a) => accounts.AsQueryable().Where(z => z == a));
But to no success; I get the identical exception each time. They always throw the same exception when I run the unit test. Since I am using an Interface to be mocked, why am I getting this exception and how do I do this properly? Thanks!
Instead of your current setup try this:
//Arrange
var repositoryMock = new Mock<IUnitOfWork>();
repositoryMock.Setup(x => x.Repository.GetQuery<Account>(
It.IsAny<Expression<Func<T, bool>>>());
.Returns(accounts.AsQueryable()); // This should not fail any more
var myClass = new MyClass(repositoryMock.Object);
In reality, you do not need to pass any concrete lambda because you are returning your list either way.
The Repository property you have shown is not of an interface type. It's some concrete class. And as the error message tells you, you cannot define expectations on non virtual methods. So what you should do instead is to work with an abstraction if you want to be able to mock it:
IRepository Repository { get; }

Categories

Resources