Как использовать 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-плетения и могут подделывать эти методы.