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

时间:2011-09-27 14:53:33

标签: fakeiteasy

我可以在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());

但是会产生警告:尝试明确指定类型参数

我目前不得不使用不理想的Ignored属性。

3 个答案:

答案 0 :(得分:2)

“匹配” - 方法需要一个lambda,但你试图将表达式传递给它。你想用“匹配”来表达什么?你在平等上匹配吗?在那种情况下,你只需写:

A.CallTo(()=&gt; repository.Single(myExpression))。返回(new Flight());

如果要将表达式约束在其他内容上,则必须将类型谓词Func<Expression<Func<Flight, bool>>, bool>传递给“匹配”方法。

答案 1 :(得分:2)

感谢Patrik,

检查表达式正是我需要做的,即解析表达式( f =&gt; 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());

然而,我不禁想到必须有一种更优雅的方式来达到同样的目的。我会把它留给另一天。

再次感谢, Michael McDowell

答案 2 :(得分:0)

我在尝试将表达式断言为参数时遇到了同样的问题,但我使用的是Moq。解决方案应该对你有用......

我对这个类似问题的答案给予了大部分赞誉: Moq Expect On IRepository Passing Expression

它基本上说你可以对表达式做一个ToString()并比较它们。它有点像hacky但它​​只有一个缺点; 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表达式的变量名,它在测试中会是相同的。