*更新编辑 - 部分解决方案 - 仍然需要帮助* - 我发现异常只是误导。它给了我这个例外,因为我得到了被嘲笑的属性被错误调用的次数。它应该被调用两次,而不是一次。那部分现在有效。
但我仍然不明白为什么不从列表中删除实体。是因为它是可查询的吗?
下面的原始问题
我一直在尝试关注this link以了解如何组织实体 框架6和6.1。
但是它没有显示如何对删除操作进行单元测试。这里是 代码我试图测试:
public void DeleteRequirement(int id)
{
Requirement requirementToDelete = GetRequirement(id);
context.Requirement.Remove(requirementToDelete);
context.SaveChanges();
}
public Requirement GetRequirement(int id)
{
return (from result in context.Requirement
where result.Id == id
select result).SingleOrDefault();
}
我的单元测试代码是
[TestMethod]
public void DeleteRequirementSuccessfully()
{
var requirements = new List<Requirement>
{
new Requirement {
Id = 1,
Title = "Requirement 1",
Description = "Requirement 1 description"
},
new Requirement {
Id = 2,
Title = "Requirement 2",
Description = "Requirement 2 description"
},
new Requirement {
Id = 3,
Title = "Requirement 3",
Description = "Requirement 3 description"
}
}
.AsQueryable();
var mockDbSet = new Mock<DbSet<Requirement>>();
var context = new Mock<RequirementsDatabaseEntities>();
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.Provider)
.Returns(requirements.Provider);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.ElementType)
.Returns(requirements.ElementType);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.Expression)
.Returns(requirements.Expression);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.GetEnumerator())
.Returns(requirements.GetEnumerator());
context.Setup(x => x.Requirement).Returns(mockDbSet.Object);
var dataAccess = new RequirementsDataAccess(context.Object);
int idToDelete = 1;
dataAccess.DeleteRequirement(idToDelete);
context.VerifyGet(x => x.Requirement, Times.Exactly(2)); // <- now verification is correct
mockDbSet.Verify(x => x.Remove(It.IsAny<Requirement>()), Times.Once());
context.Verify(x => x.SaveChanges(), Times.Once());
}
对context.VerifyGet语句的测试失败,出现以下错误
Test method DataAccessTest.RequirementUnitTest+DeleteRequirement.DeleteRequirementSuccessfully threw exception:
System.InvalidOperationException: No connection string named
'RequirementsDatabaseEntities' could be found in the application config file.
如果我评论the context.VerifyGet
行测试通过,但是
要求不会从列表中删除。有谁知道为什么?
为什么这不起作用?
答案 0 :(得分:4)
首先将requirements
的定义修改为List<Requirement>
而不是Queryable
,以便能够模拟添加或删除。并在requirements.AsQueryable()
方法中使用Setup
。
其次将此代码添加到模拟删除:
mockDbSet.Setup(m => m.Remove(It.IsAny<Requirement>())).Callback<Requirement>((entity) => requirements.Remove(entity));
因此,您可以在删除后检查requirements
列表的计数。
你的代码应该是这样的:
[TestMethod]
public void DeleteRequirementSuccessfully()
{
var requirements = new List<Requirement>
{
new Requirement {
Id = 1,
Title = "Requirement 1",
Description = "Requirement 1 description"
},
new Requirement {
Id = 2,
Title = "Requirement 2",
Description = "Requirement 2 description"
},
new Requirement {
Id = 3,
Title = "Requirement 3",
Description = "Requirement 3 description"
}
};
var mockDbSet = new Mock<DbSet<Requirement>>();
var context = new Mock<RequirementsDatabaseEntities>();
// You should use .AsQueryable() in these lines
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.Provider)
.Returns(requirements.AsQueryable().Provider);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.ElementType)
.Returns(requirements.AsQueryable().ElementType);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.Expression)
.Returns(requirements.AsQueryable().Expression);
mockDbSet.As<IQueryable<Requirement>>()
.Setup(x => x.GetEnumerator())
.Returns(requirements.GetEnumerator());
// This line should be added
mockDbSet.Setup(m => m.Remove(It.IsAny<Requirement>())).Callback<Requirement>((entity) => requirements.Remove(entity));
context.Setup(x => x.Requirement).Returns(mockDbSet.Object);
var dataAccess = new RequirementsDataAccess(context.Object);
int idToDelete = 1;
dataAccess.DeleteRequirement(idToDelete);
context.VerifyGet(x => x.Requirement, Times.Exactly(2));
//mockDbSet.Verify(x => x.Remove(It.IsAny<Requirement>()), Times.Once());
context.Verify(x => x.SaveChanges(), Times.Once());
// add this Assert
Assert.AreEqual(requirement.Count, 2);
// or
Assert.IsFalse(requirement.Any(x => x.Id == idToDelete));
}
答案 1 :(得分:2)
RequirementsDatabaseEntities.Requirement
不是虚拟方法,而是在测试方法中提供的输出不同于预期。它可能会返回空集合。修复:make RequirementsDatabaseEntities.Requirement
getter virtual
答案 2 :(得分:1)
部分解决方案 - 我发现这个例外只是误导。它给了我这个例外,因为我得到了被嘲笑的属性被错误调用的次数。它应该被调用两次,而不是一次。那部分现在有效。但我仍然不明白为什么实体没有从列表中删除。是因为它是可查询的吗?
答案 3 :(得分:0)
由于Moq使用继承来替换方法调用,因此只能模拟虚方法(或接口)。
因此要么使用你试图假冒虚拟的方法/属性,要么使用使用Jit编织工作的Isolator / JustMock等,并伪造这些方法。