Как использовать Moq в unit test операцию удаления в сущности framework 6
* Обновление Edit - Partial Solution - Помощь по-прежнему необходима *. Я обнаружил, что исключение просто вводило в заблуждение. Это давало мне это исключение, поскольку у меня было количество раз, когда издеваемое имущество было названо неправильным. Его следовало бы назвать дважды, а не раз. Эта часть работает сейчас.
Но я до сих пор не понимаю, почему сущность не удаляется из списка. Это потому, что он доступен для запроса?
Оригинальный вопрос ниже
Я пытаюсь следовать этой ссылке, чтобы узнать, как подразделение Entity
Рамки 6 и 6.1.
Однако он не показывает как unit test операцию удаления. Здесь
код, который я пытаюсь проверить:
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();
}
Мой unit test код
[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());
}
Тест не выполняется в контексте. Оператор 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
, тест проходит, но
требование не удаляется из списка. Кто-нибудь знает, почему?
- Сбой теста
- И почему, когда я прокомментирую оскорбительную строку, она проходит, но требование
не удаляется.
Почему это не работает?
Ответы
Ответ 1
Сначала отредактируйте определение requirements
как List<Requirement>
не a 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));
}
Ответ 2
- он терпит неудачу, потому что вы не можете высмеивать не виртуальный метод.
- та же проблема:
RequirementsDatabaseEntities.Requirement
не является виртуальным методом, чем обеспечивает другой вывод в тестовом методе, чем вы ожидали. он, вероятно, возвращает пустую коллекцию.
fix: make RequirementsDatabaseEntities.Requirement
getter virtual
Ответ 3
Частичное решение - Я обнаружил, что исключение просто вводит в заблуждение. Это давало мне это исключение, поскольку у меня было количество раз, когда издеваемое имущество было названо неправильным. Его следовало бы назвать дважды, а не раз. Эта часть работает сейчас. Но я до сих пор не понимаю, почему сущность не удаляется из списка. Это потому, что он доступен для запроса?
Ответ 4
Так как Moq использует наследование для замены вызовов методов, вы можете только имитировать виртуальные методы (или интерфейсы).
Таким образом, либо создавайте методы/свойства, которые вы пытаетесь подделать виртуальными, либо используйте Isolator/JustMock и т.д., которые работают с использованием Jit-плетения и могут подделывать эти методы.