3

我可以在 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 属性。

4

3 回答 3

3

“Matches”方法采用 lambda,但您正试图将表达式传递给它。你想用“匹配”电话说什么?你在平等上匹配吗?在这种情况下,您只需编写:

A.CallTo(() => repository.Single(myExpression)).Returns(new Flight());

如果您想将表达式限制在其他东西上,您必须将类型的谓词传递Func<Expression<Func<Flight, bool>>, bool>给“匹配”方法。

于 2011-09-29T19:12:04.553 回答
2

谢谢帕特里克,

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

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

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

于 2011-10-10T20:27:56.723 回答
1

我在尝试将表达式断言为参数时遇到了同样的问题,但我使用的是 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 表达式的变量名,它在测试中将是相同的。

于 2011-11-21T22:17:35.510 回答