集合已修改,枚举操作可能无法在带有 EF 的 Moq 中执行
Collection was modified, enumeration operation may not excute in Moq with EF
在进行单元测试时,在 dbset 中添加新实体后我无法从 dbset 取回集合,它抛出异常“集合已修改”
这是我的代码设置
[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);
}
在这里我无法理解我在这种情况下做错了什么。
作为参考,我正在使用这个 link:
Entity Framework 6 and Moq4: Is it possible to have a mocked DbSet retain added data for the duration of its scope?
moq Dbset 中发生错误,因为我在数据库集中添加新实体后没有更新 GetEnumerator 的引用。
public class Utility
{
public static Mock<DbSet<TEntity>> GenerateMockEntity<TEntity>(List<TEntity> entityList) where TEntity : class
{
var list = new List<TEntity>();
list.AddRange(entityList);
var query = list.AsQueryable();
var entityMockSet = new Mock<DbSet<TEntity>>() { CallBase = true};
entityMockSet.As<IQueryable<TEntity>>().Setup(m => m.Provider).Returns(query.Provider);
entityMockSet.As<IQueryable<TEntity>>().Setup(m => m.Expression).Returns(query.Expression);
entityMockSet.As<IQueryable<TEntity>>().Setup(m => m.ElementType).Returns(query.ElementType);
entityMockSet.As<IEnumerable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(query.GetEnumerator());
entityMockSet.Setup(x => x.Add(It.IsAny<TEntity>())).Callback<TEntity>(x => {
list.Add(x);
entityMockSet.As<IEnumerable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(list.GetEnumerator());
}).Returns<TEntity>(x => x);
return entityMockSet;
}
}
下列说法不正确的是:
entityMockSet.As<IEnumerable<TEntity>>()
.Setup(m => m.GetEnumerator()).Returns(query.GetEnumerator());
每个请求都返回相同的 Enumerator
,这导致您只能使用枚举器 一次 的问题,因为它之后没有任何项目。
部分解决问题的方法是每次调用 GetEnumerator
时重置枚举器,这会为您解决问题,因为您可能只使用 Add
-Method
解法:
真正解决问题的是在设置 GetEnumerator 方法时使用 Lambda:
entityMockSet.As<IEnumerable<TEntity>>()
.Setup(m => m.GetEnumerator()).Returns(() => query.GetEnumerator());
这部分很重要:
.Returns(
() => query.GetEnumerator());
因为有了这个,每次发出请求时都会返回一个新的枚举器。
在进行单元测试时,在 dbset 中添加新实体后我无法从 dbset 取回集合,它抛出异常“集合已修改”
这是我的代码设置
[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);
}
在这里我无法理解我在这种情况下做错了什么。 作为参考,我正在使用这个 link:
Entity Framework 6 and Moq4: Is it possible to have a mocked DbSet retain added data for the duration of its scope?
moq Dbset 中发生错误,因为我在数据库集中添加新实体后没有更新 GetEnumerator 的引用。
public class Utility
{
public static Mock<DbSet<TEntity>> GenerateMockEntity<TEntity>(List<TEntity> entityList) where TEntity : class
{
var list = new List<TEntity>();
list.AddRange(entityList);
var query = list.AsQueryable();
var entityMockSet = new Mock<DbSet<TEntity>>() { CallBase = true};
entityMockSet.As<IQueryable<TEntity>>().Setup(m => m.Provider).Returns(query.Provider);
entityMockSet.As<IQueryable<TEntity>>().Setup(m => m.Expression).Returns(query.Expression);
entityMockSet.As<IQueryable<TEntity>>().Setup(m => m.ElementType).Returns(query.ElementType);
entityMockSet.As<IEnumerable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(query.GetEnumerator());
entityMockSet.Setup(x => x.Add(It.IsAny<TEntity>())).Callback<TEntity>(x => {
list.Add(x);
entityMockSet.As<IEnumerable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(list.GetEnumerator());
}).Returns<TEntity>(x => x);
return entityMockSet;
}
}
下列说法不正确的是:
entityMockSet.As<IEnumerable<TEntity>>()
.Setup(m => m.GetEnumerator()).Returns(query.GetEnumerator());
每个请求都返回相同的 Enumerator
,这导致您只能使用枚举器 一次 的问题,因为它之后没有任何项目。
部分解决问题的方法是每次调用 GetEnumerator
时重置枚举器,这会为您解决问题,因为您可能只使用 Add
-Method
解法: 真正解决问题的是在设置 GetEnumerator 方法时使用 Lambda:
entityMockSet.As<IEnumerable<TEntity>>()
.Setup(m => m.GetEnumerator()).Returns(() => query.GetEnumerator());
这部分很重要:
.Returns(
() => query.GetEnumerator());
因为有了这个,每次发出请求时都会返回一个新的枚举器。