I'm having some issues setting up one of my mocks in a test that will ultimately call the setup many times but with different parameters so:
var testMock = new Mock<SomeClass>(MockBehavior.Strict);
for (int i = 30000; i <= 300000; i+=10000)
{
testMock.Setup(x => x.MethodA(SomeStaticClass.GetIt(varA, varB, i), It.IsAny<int>()))
.Returns(new List<SomeClass>());
}
So, the above doesn't work. It seems like only the last iteration will be "remembered" by the mock. How can I set up many setups on one mock like I intended to do above?
When you use external variable from inside lambda expression - it becomes "captured" by this lambda expression and its lifetime is extended. In this example lambda expression is what you pass to Setup
call, and external variable is i
loop variable. It's lifetime should be extended outside of for
loop, because you have no idea what Setup
is going to do with that variable - it might use it for a long time after for
loop and even encosing function ends. So compiler replaces this local variable with a field in compiler-generated class. Now, all lambdas you passed to Setup
in your loop reference exactly the same location - field of compiler-generated class with which i
variable was replaced.
When you call mocked function - Moq will compare argument you passed with available setups. But since all setups reference to the same location - they all reference to the last value of i
, which it had at the end of the loop.
When you copy loop variable to another variable:
for (int i = 30000; i <= 300000; i+=10000)
{
var tmp = i;
testMock.Setup(x => x.MethodA(SomeStaticClass.GetIt(varA, varB, tmp), It.IsAny<int>()))
.Returns(new List<SomeClass>());
}
It also gets captured and its lifetime is extended, but this time each loop iteration has it's own variable, so it's own instance of compiler-generated class, and now all Setup
lambdas use different value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With