Search code examples
c#entity-frameworkunit-testingin-memory-database

Collection was modified, enumeration operation may not excute in Moq with EF


While doing unit testing, i am not able to get collection back from dbset after add new entity in dbset, it throw an exception 'Collection was modified'

Here is my code setup

[TestMethod]
[TestCategory("Skill Category")]
public void Create_Skill_Category()
{
    var category = new SkillCategoryModel() { CategoryId = 3, CategoryName = "Category 3" };
    var result = skillManager.SaveSkillCategory(category);
    Assert.IsNotNull(result, "Category can't be null");
    Assert.AreEqual(category.CategoryId, result.CategoryId, "Category id must be equal");
    var categoryList = skillManager.GetCategories(); // here exception thrown
    Assert.IsTrue(categoryList.Count == 3, "Categories List must be contain three category");
}


private ISkill skillManager;
[TestInitialize]
public void Init()
{
    var category = new SkillCategory { CategoryId = 1, CategoryName = "Category 1" };

    var categories = new List<SkillCategory>
    { 
        category,
        new SkillCategory { CategoryId = 2, CategoryName = "Category 2" }
    };
    var categoryMockSet = Utility.GenerateMockEntity(categories);
    categoryMockSet.Setup(x => x.Add(It.IsAny<SkillCategory>())).Callback<SkillCategory>(x => categories.Add(x)).Returns<SkillCategory>(x => x);
    var mock = new Mock<WhoEntities>();
    mock.Setup(q => q.SkillCategories).Returns(categoryMockSet.Object);
    mock.CallBase = true;
    skillManager = new WhoGroup.DML.Managers.SkillManager(mock.Object);
}

here I'm not able to understand what I do wrong in this case. for reference I'm using this link:

Entity Framework 6 and Moq4: Is it possible to have a mocked DbSet retain added data for the duration of its scope?


Solution

  • The following statement is not correct:

    entityMockSet.As<IEnumerable<TEntity>>()
        .Setup(m => m.GetEnumerator()).Returns(query.GetEnumerator());
    

    The same Enumerator is returned for every request, which leads to the problem that you can use the enumerator only once because it has no items in it after.

    What partially fixes the problem is resetting the enumerator every time when calling the GetEnumerator which solves it for you because you may only use the Add-Method

    Solution: What really fixes the problem is to use a Lambda when setting up the GetEnumerator Method:

    entityMockSet.As<IEnumerable<TEntity>>()
        .Setup(m => m.GetEnumerator()).Returns(() => query.GetEnumerator());
    

    This part is very important: .Returns(() => query.GetEnumerator()); Because with this a new Enumerator gets returned every time a request is made.