Reputation: 9483
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.
Upvotes: 79
Views: 60475
Reputation: 359
This is because the way how are we using Return
method
if we are using Return(GetObject2(object1))
object1 never got initialized from callback, so it will fail to convert to Object2
The Right way to use like this Return(()=> GetObject2())
, we have make Return method specifies a function that will calculate the value to return from the method
Don't forgot to use funcation key ()=>
Below Example, For your reference
var object1= new List<Object>();
mockObj.Setup(_ =>_.GetMethod(It.IsAny<List<Object>>()))
.Callback<List<Object>>((obj1) =>
{
object1= obj1;
})
.Returns(()=> GetObject2(object1));
private List<Object2> GetObject2(List<Object> object1){
return object1.select(_=> new Object2())
}
Upvotes: 0
Reputation: 233150
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>());
Upvotes: 126
Reputation:
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>();
});
Upvotes: 29