Reputation: 16685
I'm writing a unit test that mocks out the IDbSet
properties of the DbContext; however, I seem to be getting some strange results.
Here's the code where I mock out the data:
var myData1 = new List<MyData1>()
{
new MyData1() { Id = 2, Test = "test" },
new MyData1() { Id = 3, Test = "test" },
new MyData1() { Id = 4, Test = "test" }
}.AsQueryable();
IDbSet<MyData1> myDbSet = Substitute.For<IDbSet<MyData1>>();
myDbSet.Provider.Returns(myData1.Provider);
myDbSet.Expression.Returns(myData1.Expression);
myDbSet.ElementType.Returns(myData1.ElementType);
myDbSet.GetEnumerator().Returns(myData1.GetEnumerator());
myDbContext.MyData1.Returns(myDbSet);
. . .
myDbContext.MyData2.Returns(myDbSet2);
. . .
myDbContext.MyData3.Returns(myDbSet3);
When I come to interrogate the data; for example:
using (IMyDbContext myDbContext = _dbContextGenerator.GenerateDbContext())
{
var myData = myDbContext.MyData1.ToList();
}
_dbContextGenerator
is simply substituted to return my test DbContext, instead of the real one:
IDbContextGenerator dbContextGenerator = Substitute.For<IDbContextGenerator>();
dbContextGenerator.GenerateDbContext().Returns(myDbContext);
This seems to work; however, if I call the method twice; it doesn't. So:
using (IMyDbContext myDbContext = _dbContextGenerator.GenerateDbContext())
{
myData = myDbContext.MyData1.ToList();
}
Assert.Equal(3, myData.Count());
Works; however:
using (IMyDbContext myDbContext = _dbContextGenerator.GenerateDbContext())
{
myData = myDbContext.MyData1.ToList();
}
using (IMyDbContext myDbContext = _dbContextGenerator.GenerateDbContext())
{
myData = myDbContext.MyData1.ToList();
}
Assert.Equal(3, myData.Count());
Does not. I get no data returned; however, if I debug the line, I can see that:
myDbContextMyData1.Provider
Contains the correct test data.
Please could someone point me in the right direction on this?
Upvotes: 3
Views: 432
Reputation: 247008
The problem is
myDbSet.GetEnumerator().Returns(myData1.GetEnumerator());
Which will return the same enumerator instance every time it is called.
And since the enumerator is forward only, it will need to be reset. Calling it more than once without resetting will exhibit the described behavior of only being able to enumerate once because the pointer is at the end.
Use a delegate call back so that it is invoked every time the mock is called to return a new enumerator every time GetEnumerator()
is called.
myDbSet.GetEnumerator().Returns(_ => myData1.GetEnumerator());
Now enumerating the mock multiple times should then behave as expected.
Upvotes: 1