Reputation: 30355
I have a method that accepts an IEnumerable
:
MyMethod(IEnumerable<MyClass> myParameter)
Now I am writing this code to mock the service:
var array1 = new MyClass[0];
var array2 = new MyClass[0];
_service
.Setup(s => s.MyMethod(array1))
.Returns(value1);
_service
.Setup(s => s.MyMethod(array2))
.Returns(value2);
And finally I am doing two calls to the service with both arrays inside system under test:
_service.MyMethod(array1);
_service.MyMethod(array2);
What I do expect is to get value1
and value2
from these calls, but in practice the latter call overrides the first one and I only get value2
from both calls.
Is this a bug in Moq or is this a feature that setup treats IEnumerable
not as a separate object but rather tries to expand it and compare all elements or something (resulting in two empty arrays being the same setup call)?
Upvotes: 3
Views: 627
Reputation: 9519
The behaviour you describe is the default behaviour of the moq
, you can see it here. It indeed unfold enumerable and invoke IEnumerable.SequenceEqual
. However that is default behaviour(if you setup using an instance, Constant
matcher) and you could override it. The one approach is what Owen suggested to use It.Is<T>
matcher, e.g.
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array1)))
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array2)))
Notice that ==
by default do ReferenceEquals()
so this will make different non overridable setups.
Upvotes: 2
Reputation: 11871
When you create multiple setups on a method with Moq, each subsequent setup will replace the previous setup unless the setups are conditional (they specify certain conditions on the arguments). See this answer.
You can fix your code by specifying that the arguments must match the ones you intend to pass:
[Test]
public void MyTest()
{
var service = new Mock<MyClass>();
var array1 = new MyClass[0];
var array2 = new MyClass[0];
var value1 = "value1";
var value2 = "value2";
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array1))).Returns(value1);
service.Setup(s => s.MyMethod(It.Is<IEnumerable<MyClass>>(e => e == array2))).Returns(value2);
Assert.AreEqual(value1, service.Object.MyMethod(array1));
Assert.AreEqual(value2, service.Object.MyMethod(array2));
}
Upvotes: 2