【问题标题】:Moq.Mock<Expression<Func<T,bool>>>() - how to setup expressions into a Mock using MoqMoq.Mock<Expression<Func<T,bool>>>() - 如何使用 Moq 将表达式设置为 Mock
【发布时间】:2011-12-20 09:56:19
【问题描述】:

我已经阅读了很多关于此主题的其他 QA,但我仍然无法找到解决问题的方法,因此我决定公开我的案例。

我有这个界面

public interface IRepository<T> where T : class, IEntity 
{
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);
    T FindIncluding(int id, params Expression<Func<T, object>>[] includeProperties);
}

这是包含我要设置的 Mock 的方法的基本结构

public PeopleController CreatePeopleController()
{
    var mockUnitofWork = new Mock<IUnitOfWork>();
    var mockPeopleRepository = new Mock<IRepository<Person>>();

    mockPeopleRepository.Setup(r=>r.Find().Returns(new Person(){});
    mockUnitofWork.Setup(p => p.People).Returns(mockPeopleRepository.Object);
    return new PeopleController(mockUnitofWork.Object);
}

我一直在尝试使用这种方式设置 Mock:

public PeopleController CreatePeopleController()
{
    var mockUnitofWork = new Mock<IUnitOfWork>();
    var mockPeopleRepository = new Mock<IRepository<Person>>();

    mockPeopleRepository.Setup(r=>r.Find(It.isAny<Expression<Func<Person,bool>>>()).Single()).Returns(new Person(){});
    mockUnitofWork.Setup(p => p.People).Returns(mockPeopleRepository.Object);
    return new PeopleController(mockUnitofWork.Object);
}

但是系统总是抛出同样的异常“System.NotSupportedException:表达式引用了一个不属于mocked对象的方法......”

另外我想补充一点,我正在使用 MSTest 和 Moq

我知道使用 Expression 设置 Mock 并不容易且不推荐,但这对我来说非常重要,因为“查找”是我在我的应用程序中经常使用的一种方法

【问题讨论】:

    标签: .net unit-testing tdd mocking moq


    【解决方案1】:

    问题是您试图将 Single() 扩展方法设置为模拟的一部分。设置调用需要有你的方法的结果——而不是你的方法的结果,随后应用了一些扩展方法。我会试试这个:

        [TestMethod]
        public void MyTestMethod()
        {
            var myMock = new Mock<IRepository<Person>>();
            myMock.Setup(r => r.Find(It.IsAny<Expression<Func<Person, bool>>>())).Returns(new List<Person>() { new Person() }.AsQueryable());
    
            Assert.IsTrue(true);
        }
    

    在这里,您只是使用 setup 对 Find() 方法进行存根,并在 Returns() 子句中执行所有其他操作。我一般会建议这种方法。设置应该准确地反映您的模拟项目,并且您可以为 Returns()(或 Throws() 或其他)调用执行一堆黑魔法,以使其执行您想要的操作。

    (当我在 VS 中运行该代码时,它通过了,所以它没有抛出异常)

    【讨论】:

    • @gustavotroconis 如果此答案解决了您的问题,您可以通过单击旁边的复选标记来接受它。当您提出更多问题时,您的头像下方会出现一个“接受百分比”,而较高的百分比会鼓励其他人回答您的问题。
    【解决方案2】:

    使用 Moq 的 It.IsAny&lt;&gt; 而不使用 .CallBack 会强制您编写测试未涵盖的代码。相反,它允许任何查询/表达式通过,从单元测试的角度来看,您的模拟基本上毫无用处。

    解决方案:您要么需要使用回调来测试表达式,要么需要更好地约束您的模拟。无论哪种方式都是混乱和困难的。只要我一直在练习 TDD,我就一直在处理这个问题。我终于拼凑了一个帮助类,以使其更具表现力且不那么混乱。这是最终结果(适用于您的示例):

    mockPeopleRepository
      .Setup(x => x.Find(ThatHas.AnExpressionFor<Person>()
        .ThatMatches(correctPerson)
        .And().ThatDoesNotMatch(deletedPerson)
        .Build()))
      .Returns(_expectedListOfPeople); 
    

    这是讨论它并提供源代码的博客文章:http://awkwardcoder.com/2013/04/24/constraining-mocks-with-expression-arguments/

    【讨论】:

      猜你喜欢
      • 2012-01-20
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-02
      相关资源
      最近更新 更多