为什么这个带有表达式的模拟不匹配
本文关键字:bool 不匹配 模拟 Func 表达式 为什么 | 更新日期: 2023-09-27 18:34:18
我是模拟新手,我正在尝试做这个模拟示例:
存储库.cs
public class Repository : IRepository
{
public List<Person> GetForExpression(Expression<Func<Person,bool>> expression )
{
... //get person from orm using expression
}
}
个人服务.cs
public class PersonService
{
private IRepository _repository;
public PersonService(IRepository repository)
{
_repository = repository;
}
public List<Person> GetAllPersonsWith18More()
{
var result = _repository.GetForExpression(x => x.Age > 18);
return result;
}
}
测试:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var moqRepository = new Mock<IRepository>();
var service = new PersonService(moqRepository.Object);
Expression<Func<Person, bool>> criteria = y => y.Age 18;
moqRepository.Setup(x => x.GetForExpression(It.Is<Expression<Func<Person, bool>>>(y => y == criteria))).Returns(new List<Person>());
service.GetAllPersonsWith18More();
moqRepository.VerifyAll();
}
}
如果我使用此设置可以工作: moqRepository.Setup(x => x.GetForExpression(It.IsAny>>())).返回(新列表());
但我想使用更具体的标准,这只是我用来证明我需要什么的一个例子。
这个例子不匹配,任何人都可以帮助理解为什么并解决这个问题吗?
如果需要测试委托,我通常会将它们应用于任何测试对象。为了测试 PersonService,我宁愿使用以下包含两个测试示例的代码。
[TestClass]
public class UnitTest2
{
private Mock<IRepository> moqRepository;
private PersonService service;
[TestInitialize]
public void TestInitialize()
{
moqRepository = new Mock<IRepository>();
service = new PersonService(moqRepository.Object);
}
[TestMethod]
public void TestMethod3()
{
// arrange
var persons = new List<Person>
{
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<Expression<Func<Person, bool>>>()))
.Returns<Expression<Func<Person, bool>>>(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<Func<Person, bool>> criteria = x => x.Age > 18;
moqRepository
.Setup(x => x.GetForExpression(It.IsAny<Expression<Func<Person, bool>>>()))
.Returns(new List<Person>())
.Callback<Expression<Func<Person, bool>>>(expr =>
{
var persons = new List<Person>
{
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();
}
}
表达式不能这样比较。如果你想非常详细地匹配表达式,你需要将传递给你的模拟的表达式解析为树(如本答案所述)。结果看起来像这样(FuncTest.FuncEqual
可以在上一个答案中找到):
moqRepository
.Setup(x => x.GetForExpression(ExpressionMatches(criteria))
.Returns(new List<Person>());
// ...
public static Expression<Func<TSource, TValue>> ExpressionMatches(Expression<Func<TSource, TValue>> expr)
{
return Match.Create<Expression<Func<TSource, TValue>>(actualExpr => FuncTest.FuncEqual(expr, actualExpr));
}
表达式不具有可比性,因此即使表达式树完全匹配,== 也会返回 false:
int criteria = 5;
Expression<Func<int, bool>> criteria1 = y => y == criteria;
Expression<Func<int, bool>> criteria2 = y => y == criteria;
System.Diagnostics.Debug.WriteLine(criteria1 == criteria2); // false
作为解决方法,您可以调用表达式。ToString() 和比较字符串表示形式:比较简单的 lambda 表达式与最小起订量。