使用表达式树作为参数约束

本文关键字:参数约束 表达式 | 更新日期: 2023-09-27 18:09:42

我可以在FakeIteasy CallTo断言中使用表达式树作为参数约束吗?

给定接口上具有以下签名的方法:

interface IRepository<TEntity>
{
    TEntity Single(Expression<Func<TEntity, bool>> predicate);

在代码中被这样调用:

Flight flight = repository.Single(f => f.ID == id);

我想到了这样一个单元测试:

Expression<Func<Flight, bool>> myExpression = flight => flight.ID == 1;
A.CallTo(() => repository.Single(
                  A<Expression<Func<Flight, bool>>>.That.Matches(myExpression)))
                  .Returns(new Flight());

但是这会产生一个警告:尝试显式指定类型参数

我目前不得不使用忽略属性,这是不理想的。

使用表达式树作为参数约束

"Matches"-方法接受lambda,但您试图将表达式传递给它。你叫我"配对"是想说什么?你们是平等配对吗?在这种情况下,你只需写:

callto (() => repository.Single(myExpression))。返回(新飞行());

如果你想把表达式约束在其他东西上,你必须传递一个类型为:Func<Expression<Func<Flight, bool>>, bool>的谓词到"Matches"方法。

谢谢patrick,

检查表达式正是我需要做的,即解析表达式(f => f.ID == id)并执行==的右侧以获得其运行时值。

在代码中是这样的:

A.CallTo(() => flightRepository.Single(A<Expression<Func<Flight, bool>>>.That
                .Matches(exp => Expression.Lambda<Func<int>>(((BinaryExpression)exp.Body).Right).Compile().Invoke() == 1)))
                .Returns(new Flight());

然而,我忍不住想一定有一种更优雅的方式来达到同样的目的。不过我还是改天再说吧。

再次感谢,迈克尔·麦克道尔

我有同样的问题,而试图断言表达式作为一个参数,但我正在使用Moq。解决方案应该也适用于你…

我把大部分功劳归功于对一个类似问题的回答:Moq Expect On IRepository Passing Expression

它基本上说你可以对表达式执行ToString()并比较它们。这有点俗气,但它只有一个缺点; lambda表达式中的变量名必须匹配

    [Test]
    public void TestWhichComparesExpressions()
    {
        // setup
        _mockRepository.Setup(x => x.GetByFilter(MatchQuery())).Returns(new List<Record>());
        // execute
        var records = _service.GetRecordsByFilter();
        // assert
        Assert.IsNotNull(records);
        Assert.AreEqual(0, records.Count());
    }
    private static Expression<Func<DomainRecord, bool>> MatchQuery()
    {
        return MatchExpression(ServiceClass.QueryForTheRecords); // constant
    }
    // https://stackoverflow.com/questions/288413/moq-expect-on-irepository-passing-expression/1120836#1120836
    private static Expression<Func<DomainRecord, bool>> MatchExpression(Expression<Func<DomainRecord, bool>> expression)
    {
        return It.Is<Expression<Func<DomainRecord, bool>>>(e => e.ToString() == expression.ToString());
    }

我决定将表达式放入使用它的类的常量中,以保证如果有人更改了lambda表达式的变量名,则在测试中它将是相同的。