.net 最小起订量模拟<;表达式<;Func<;T、 布尔>&燃气轮机&燃气轮机;()-如何使用Moq将表达式设置为模拟

.net 最小起订量模拟<;表达式<;Func<;T、 布尔>&燃气轮机&燃气轮机;()-如何使用Moq将表达式设置为模拟,.net,unit-testing,tdd,mocking,moq,.net,Unit Testing,Tdd,Mocking,Moq,我已经读了很多其他QA关于这个话题的文章,但我仍然找不到解决问题的方法,所以我决定公开我的案例 我有这个接口 public interface IRepository<T> where T : class, IEntity { IQueryable<T> Find(Expression<Func<T, bool>> predicate); T FindIncluding(int id, params Expression<F

我已经读了很多其他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);
}
公共接口i假设,其中T:class,icity
{
IQueryable查找(表达式谓词);
T FindIncluding(int-id,参数表达式[]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);
}
公共PeopleController CreatePeopleController() { var mockUnitofWork=new Mock(); var mockPeopleRepository=new Mock(); mockPeopleRepository.Setup(r=>r.Find().Returns(newperson(){}); Setup(p=>p.People).Returns(mockPeopleRepository.Object); 返回新的PeopleController(mockUnitofWork.Object); } 我一直在尝试使用以下方式设置模拟:

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);
}
公共PeopleController CreatePeopleController() { var mockUnitofWork=new Mock(); var mockPeopleRepository=new Mock(); mockPeopleRepository.Setup(r=>r.Find(It.isAny()).Single()).Returns(newperson(){}); Setup(p=>p.People).Returns(mockPeopleRepository.Object); 返回新的PeopleController(mockUnitofWork.Object); } 但是系统总是抛出相同的异常“system.NotSupportedException:表达式引用不属于模拟对象的方法…”

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


我知道使用表达式设置模拟并不容易,也不推荐使用,但这对我来说非常重要,因为“查找”是我在应用程序中经常使用的一种方法。问题是,您正在尝试设置单个()作为模拟的一部分的扩展方法。安装调用需要有方法的结果,而不是随后应用某个扩展方法的方法的结果。我会尝试以下方法:

    [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);
    }
[TestMethod]
公共void MyTestMethod()
{
var myMock=new Mock();
myMock.Setup(r=>r.Find(It.IsAny()).Returns(newlist(){newperson()}.AsQueryable());
Assert.IsTrue(真);
}
在这里,您只需将Find()方法与setup连接起来,并在Returns()子句中执行所有其他操作。我建议通常使用这种方法。安装程序应该准确地镜像模拟的项,并且您可以对Returns()调用(或Throws()或其他任何调用)执行一系列黑魔法,以使其执行您想要的操作


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

使用Moq的
它。没有
回调的IsAny
强制您编写测试中未包含的代码。相反,它允许任何查询/表达式通过,从单元测试的角度来看,您的模拟基本上没有用处

解决方案:你要么需要使用回调来测试表达式,要么需要更好地约束你的模拟。任何一种方法都是混乱和困难的。我在练习TDD的过程中就一直在处理这个问题。我最终创建了一个帮助器类,使它更具表现力,更不混乱。下面是最终结果(根据您的示例改编):

mockPeopleRepository
.Setup(x=>x.Find(thahas.AnExpressionFor())
.that匹配(正确的人)
.和()。不匹配(删除个人)
.Build())
.返回(_expectedListOfPeople);

下面是一篇关于这个问题的博客文章,并给出了源代码:

@gustavotroconis如果这个答案解决了你的问题,你可以通过点击旁边的复选标记来接受它。当你问更多问题时,你的头像下面会出现一个“接受%”,更高的%会鼓励其他人回答你的问题。
mockPeopleRepository
  .Setup(x => x.Find(ThatHas.AnExpressionFor<Person>()
    .ThatMatches(correctPerson)
    .And().ThatDoesNotMatch(deletedPerson)
    .Build()))
  .Returns(_expectedListOfPeople);