Settings variable values in a Moq Callback() call - c#

I think I may be a bit confused on the syntax of the Moq Callback methods. When I try to do something like this:
IFilter filter = new Filter();
List<IFoo> objects = new List<IFoo> { new Foo(), new Foo() };
IQueryable myFilteredFoos = null;
mockObject.Setup(m => m.GetByFilter(It.IsAny<IFilter>()))
.Callback( (IFilter filter) => myFilteredFoos = filter.FilterCollection(objects))
.Returns(myFilteredFoos.Cast<IFooBar>());
This throws a exception because myFilteredFoos is null during the Cast<IFooBar>() call. Is this not working as I expect? I would think FilterCollection would be called and then myFilteredFoos would be non-null and allow for the cast.
FilterCollection is not capable of returning a null which draws me to the conclusion it is not being called. Also, when I declare myFilteredFoos like this:
Queryable myFilteredFoos;
The Return call complains that myFilteredFoos may be used before it is initialized.

This is because the code in the Returns method is evaluated immediately; that is, when the Setup method is being invoked.
However, the callback isn't being invoked until the GetByFilter method is invoked.
Luckily, the Returns method is overloaded so that you can defer its execution as well:
mockObject.Setup(m => m.GetByFilter(It.IsAny<IFilter>()))
.Callback((IFilter filter) =>
myFilteredFoos = filter.FilterCollection(objects))
.Returns(() => myFilteredFoos.Cast<IFooBar>());
However, you don't need to save the value in a callback, because you can just get the parameter value directly in the Returns method:
mockObject.Setup(m => m.GetByFilter(It.IsAny<IFilter>()))
.Returns((IFilter filter) =>
filter.FilterCollection(objects).Cast<IFooBar>());

You can just take the parameter in the return value...
mockObject
.Setup(m => m.GetByFilter(It.IsAny<IFilter>()))
.Returns((IFilter filter) =>
{
myFilteredFoos = filter.FilterCollection(objects);
return myFilteredFoos.Cast<IFooBar>();
});

Related

Mock calling with return type delegate return test method delegate but not delegates from setup

There is a mock for a certain method, in it, depending on the input parameter, I determine which delegate will return. The problem is the following - when this method is called, the delegate set in returns is not called, but the delegate of the TEST method is returned.
How is it?
Mock setup
actionsProvider
.Setup(x => x.GetDelegateByCommandNameWithoutParams(It.IsAny<string>()))
.Returns((string x) =>
{
if (x == testCommand)
return Delegate.CreateDelegate(typeof(Func<int>),
typeof(ExecuteCodeLinesCommandTests).GetMethod(testMethod));
else if (x == testCommand2)
return Delegate.CreateDelegate(typeof(Func<int, int, int, int>),
typeof(ExecuteCodeLinesCommandTests).GetMethod(testMethod2));
else return null;
});
Mocking interface
public interface ICommandActionsProvider
{
public Delegate? GetDelegateByCommandNameWithoutParams(string commandName);
}
Method call
Delegate? del = commandActionProvider.GetDelegateByCommandNameWithoutParams(commandName);
Call return TEST method delegate, not from setup
I've already tried removing the delegate from returns, leaving just one return value. In this case, mock was called.
Instead of having branching inside the Returns try to create two Setups
actionsProvider
.Setup(x => x.GetDelegateByCommandNameWithoutParams(testCommand))
.Returns(Delegate.CreateDelegate(typeof(Func<int>),
typeof(ExecuteCodeLinesCommandTests).GetMethod(testMethod)));
actionsProvider
.Setup(x => x.GetDelegateByCommandNameWithoutParams(testCommand2))
.Returns(Delegate.CreateDelegate(typeof(Func<int, int, int, int>),
typeof(ExecuteCodeLinesCommandTests).GetMethod(testMethod2)));
If your default mock behaviour is loose then you will receive null for non-matching method calls. (If it is strict then it will throw exception.)

Stubbing function expression of repository object using Rhino Mocks

I'm using Rhino Mocks to unit test a service method that makes the following call:
var form = Repo.GetOne<Form>(f => f.Id == formId, "FormTemplate, Event");
The Repo.GetOne method signature is:
TEntity GetOne<TEntity>(
Expression<Func<TEntity, bool>> filter = null,
string includeProperties = null)
where TEntity : class, IEntity;
So far I have only managed to do this by ignoring the Function Expression argument:
_mockRepo.Stub(
r =>
r.GetOne<Form>(
Arg<Expression<Func<Form, bool>>>.Is.Anything,
Arg<string>.Is.Equal("FormTemplate, Event")))
.Return(form);
How do I stub the Repo.GetOne method in order to set the return value when the method is called with arguments f => f.Id == formId, "FormTemplate, Event"?
When you setup Stub/Mocks, the value used for the arguments must return true when you call mockArg.Equals(runtimeArg). Your Func<> isn't going to do that, so you're best bet is to use the Arg<T>.Matches() constraint, which takes a function that, given the stub inputs, returns true if the runtime input are a match.
Unfortunately, looking at the contents of the Func<T> delegate is not straightforward. (Take a look at https://stackoverflow.com/a/17673890/682840)
var myArgChecker = new Function<Expression<Func<Form, bool>>, bool>(input =>
{
//inspect input to determine if it's a match
return true; //or false if you don't want to apply this stub
});
_mockRepo.Stub(
r =>
r.GetOne<Form>(
Arg<Expression<Func<Form, bool>>>.Matches(input => myArgChecker(input)),
Arg<string>.Is.Equal("FormTemplate, Event")))
.Return(form);

When unit testing, how do I mock a return null from async method?

Normally, I mock my repo like so:
var repository = new Mock<ISRepository>();
repository.Setup(r => r.GetMemberAsync(email))
.Returns(Task.FromResult(new Member
{
FirstName = firstName,
LastName = lastName
}));
But, in my code, I check to see if the member is not found, i.e. GetMemberAsync returns null. How do I mock this?
I tried:
var repository = new Mock<ISRepository>();
repository.Setup(r => r.GetMemberAsync(email))
.Returns(Task.FromResult<object>(null));
but I get a compile error.
You get a compiler error because you return a task that doesn't match the type the async method returns. You should return Task<Member> instead of simply Task<object>:
repository.Setup(r => r.GetMemberAsync(email)).Returns(Task.FromResult<Member>(null));
It is also possible to return the result without using the Task class.
repository
.Setup(r => r.GetMemberAsync(email))
.ReturnsAsync((Member)null);
Old question but you can also do this which I think it cleaner:
Assuming the default value of your object is null you can also use:
default(<insert object type here>)
e.g.
default(Member)
default(List<string>)
etc.
Full Example:
var myRepo = new Mock<IMyRepo>();
myRepo
.Setup(p => p.GetAsync("name"))
.ReturnsAsync(default(List<string>));

Moq callback for ReturnsAsync

I'm currently refactoring API to async actions and I need to refactor the tests for async. I have similar case as in the Moq documentation:
// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
.Returns(() => calls)
.Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThing());
And I need to change it to:
// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThingAsync())
.ReturnsAsync(calls)
.Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThingAsync());
But as the ReturnAsync() doesn't support lambda yet, the callback is called, but apparently in different context and thus the variable remains the value for the next call instead of being increased. Is there a way how to solve this?
In the first example you are passing a lambda to the Returns method, and that lambda is re-evaluated each time the mocked method is called. Because of this, you can actually combine Callback and Returns
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
.Returns(() => calls++);
Console.WriteLine(mock.Object.GetCountThing());
In the second example you are passing the value 0 into the ReturnsAsync method, so that is why the mock returns zero each time. Although ReturnsAsync doesn't support passing a Func, you can still use Returns like so
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThingAsync())
.Returns(() => Task.FromResult(calls++));
Console.WriteLine(await mock.Object.GetCountThingAsync());

Mock Dependency Injection repository with filter

trying to mock repository :
var expMock = new Mock<IEntityRepository>();
expMock.Setup(s => s.GetMany(It.IsAny<Expression<Func<Entity, bool>>>()))
.Returns<IQueryable<Entity>>(r =>
new List<Entity>{ new Entity() } }.AsQueryable());
but when i call it:
IEnumerable<Entity> source = _entityRepository.GetMany(w => w.IsActive);
i get an exception:
System.ArgumentException : Object of type
'System.Linq.Expressions.Expression1[System.Func2[Entity,System.Boolean]]'
cannot be converted to type 'System.Linq.IQueryable`1[Entity]'.
Simply return value which you want your mocked method to return. In your case it will be IQueryable:
expMock.Setup(s => s.GetMany(It.IsAny<Expression<Func<Entity, bool>>>()))
.Returns(new List<Entity>{ new Entity() }.AsQueryable());
Generic parameter of Returns method is a type of the argument of invoked method. Returns<IQueryable<Entity>> means that GetMany method should be invoked with parameter of type IQueryable<Entity> which is not true of course. That's why you get this exception.
Method argument is the expression, so correct mock setup should look like:
.Returns<Expression<Func<Entity, bool>>>(e =>
new List<Entity> { new Entity() }.AsQueryable());
But thus you don't need method argument for providing returned result, use code above.
Your Returns() statement is binding your Func to be returned when GetMany() is called, not evaluating the expression and returning the result. It should work if you take out the r=>. You can probably get away without the type parameter as well.

Categories