为什么这个带有Expression <Func 的模拟不匹配?

我是模拟的新手,我试图做这个模拟示例:

Repository.cs

public class Repository : IRepository { public List GetForExpression(Expression<Func> expression ) { ... //get person from orm using expression } } 

PersonService.cs

 public class PersonService { private IRepository _repository; public PersonService(IRepository repository) { _repository = repository; } public List GetAllPersonsWith18More() { var result = _repository.GetForExpression(x => x.Age > 18); return result; } } 

测试:

 [TestClass] public class UnitTest1 { [TestMethod] public void TestMethod1() { var moqRepository = new Mock(); var service = new PersonService(moqRepository.Object); Expression<Func> criteria = y => y.Age 18; moqRepository.Setup(x => x.GetForExpression(It.Is<Expression<Func>>(y => y == criteria))).Returns(new List()); service.GetAllPersonsWith18More(); moqRepository.VerifyAll(); } } 

如果我使用此设置工作:moqRepository.Setup(x => x.GetForExpression(It.IsAny >>()))。返回(new List());

但我想使用更具体的标准,这只是我展示我需要的一个例子。

这个例子不匹配,任何人都可以帮助理解为什么并解决这个问题?

如果需要测试代理,我通常将它们应用于任何测试对象。 为了测试PersonService,我宁愿使用包含两个测试示例的以下代码。

 [TestClass] public class UnitTest2 { private Mock moqRepository; private PersonService service; [TestInitialize] public void TestInitialize() { moqRepository = new Mock(); service = new PersonService(moqRepository.Object); } [TestMethod] public void TestMethod3() { // arrange var persons = new List { new Person { Age = 0 }, new Person { Age = 1 }, new Person { Age = 17 }, new Person { Age = 18 }, new Person { Age = 19 }, new Person { Age = 100 } }; moqRepository .Setup(x => x.GetForExpression(It.IsAny>>())) .Returns>>(expr => persons.Where(expr.Compile()).ToList()); // act var result = service.GetAllPersonsWith18More(); // assert moqRepository.VerifyAll(); result.Should().BeEquivalentTo(persons.Where(x => x.Age > 18)); } [TestMethod] public void TestMethod4() { // arrange Expression> criteria = x => x.Age > 18; moqRepository .Setup(x => x.GetForExpression(It.IsAny>>())) .Returns(new List()) .Callback>>(expr => { var persons = new List { new Person { Age = 0 }, new Person { Age = 1 }, new Person { Age = 17 }, new Person { Age = 18 }, new Person { Age = 19 }, new Person { Age = 100 } }; persons.Where(expr.Compile()).Should().BeEquivalentTo(persons.Where(criteria.Compile())); }); // act service.GetAllPersonsWith18More(); // assert moqRepository.VerifyAll(); } } 

表达式不具有可比性,因此即使表达式树完全匹配,==也将返回false:

 int criteria = 5; Expression> criteria1 = y => y == criteria; Expression> criteria2 = y => y == criteria; System.Diagnostics.Debug.WriteLine(criteria1 == criteria2); // false 

作为解决方法,您可以调用expression.ToString()并比较字符串表示: 将简单Lambda表达式与Moq进行比较 。

表达式无法像那样进行比较。 如果要在很多细节中匹配表达式,则需要将传递给mock的表达式解析并解析它的树(如本答案中所述 )。 结果看起来像这样(在上一个答案中可以找到FuncTest.FuncEqual ):

 moqRepository .Setup(x => x.GetForExpression(ExpressionMatches(criteria)) .Returns(new List()); // ... public static Expression> ExpressionMatches(Expression> expr) { return Match.Create>(actualExpr => FuncTest.FuncEqual(expr, actualExpr)); }