Reputation: 6142
If I mock a collection letting Moq implement the GetEnumerator calling back the GetEnumerator of a different collection, I get the correct results if I invoke MoveNext/Current and foreach.
When I try to use the Result View from the Visual Studio debugger, I get "Enumeration yielded no results". Is there a reason for this? Isn't it just enumerating and caching it?
var dbParameterMock1 = CreateDbParameterMock("@Parameter1", 1);
var dbParameters = new ArrayList { dbParameterMock1.Object };
var dbParameterCollectionMock = new Mock<DbParameterCollection>();
dbParameterCollectionMock.Setup(collection => collection.GetEnumerator()).Returns(dbParameters.GetEnumerator());
return dbParameterCollectionMock;
Upvotes: 0
Views: 301
Reputation: 6142
Thanks to @Patrick Steele who helped me realize my mistake:
The problem is here:
[...].Returns(dbParameters.GetEnumerator());
Which is getting the enumerator instance and using it for the mock. Once used the first time it is probably disposed and somehow set to null.
As suggested, the Result View is enumerating twice and presenting results from the second time which are null (and a question mark as obviously there is something wrong with the disposed enumerator).
To survive subsequent enumerations, it needs to query for a new one every time using a lambda for the mock:
[...].Returns(() => dbParameters.GetEnumerator());
Upvotes: 0
Reputation: 14677
It's definitely got something to do with the way the debugger interacts with the object. I recreated your example in a console application but added a callback so I would know each time GetEnumerator
is called:
var dbParameterMock1 = new Mock<DbParameter>().SetupAllProperties();
dbParameterMock1.Object.ParameterName = "@Parameter1";
dbParameterMock1.Object.Value = 1;
var dbParameters = new ArrayList { dbParameterMock1.Object };
var dbParameterCollectionMock = new Mock<DbParameterCollection>();
dbParameterCollectionMock.Setup(collection => collection.GetEnumerator())
.Returns(dbParameters.GetEnumerator())
.Callback(() => Console.WriteLine("GetEnumeratorCalled"));
foreach (DbParameter p in dbParameterCollectionMock.Object)
{
Console.WriteLine(p.ParameterName);
}
If I set a breakpoint on the foreach, run the code and then use the debugger to view the dbParameterCollectionMock.Object
, I'll see GetEnumerator()
is called twice. The first one would return your actual enumerator of the ArrayList while subsequent calls would return null. It seems like the debugger is enumerating the second call, hence the "Enumeration yielded no results" message.
Consequently, in the case above where the debugger has already called the one mocked call of GetEnumerator
, if I continue running the app, the foreach completes without doing anything. Again, because the debugger has already called the one, mocked, GetEnumerator
.
Not a true "answer" but may help shed some light on what you're seeing.
Upvotes: 1