简体   繁体   English

Moq:获取表达式谓词的参数值

[英]Moq: Get parameter value of expression predicate

I'm new to using Moq and I'm trying to get the value passed into a Moq'd method to use in the Returns method.我是使用 Moq 的新手,我正在尝试将值传递给 Moq'd 方法以在 Returns 方法中使用。

I was doing the following with success.我正在成功地执行以下操作。

        _repositoryMock.Setup(x => x.GetByOrderId(It.IsAny<string>()))
            .Returns((string id) => Task.FromResult(
                new Order
                {
                    Id = id
                }));

Usage in code:代码中的用法:

var order = _repository.GetByOrderId("123");

The above worked fine and the id passed into the Returns method is the same ID I passed into the GetByOrderId method in my code.以上工作正常,传递给 Returns 方法的id与我在代码中传递给 GetByOrderId 方法的 ID 相同。

However, I would like to make my repository more generic so I want to change my GetByOrderId to FindFirstOrDefault that takes an expression predicate instead of an ID.但是,我想让我的存储库更通用,所以我想将我的 GetByOrderId 更改为 FindFirstOrDefault,它采用表达式谓词而不是 ID。

Usage like this:用法如下:

var order = _repository.FindFirstOrDefault( o => x.Id == "123");

With unit test changed to this:单元测试更改为:

_repositoryMock.Setup(moq => moq.FindFirst(It.IsAny<Expression<Func<Order, bool>>>()))
            .Returns((Expression<Func<Order, bool>> expression) => Task.FromResult(
                new Order
                {
                    Id = // ... HOW TO GET ID LIKE THE FIRST SAMPLE?
                }));

So how can I get to that ID?那么我怎样才能获得那个ID呢? The "123". “123”。 Is there any way?有什么办法吗?

I found a work around.我找到了解决办法。

I just set up a list of Order that had all the values I knew would be in my expected result an then I applied the expression to that list to get the item I wanted.我只是设置了一个Order列表,其中包含我知道在预期结果中的所有值,然后我将表达式应用于该列表以获取我想要的项目。

var expected = // INIT MY EXPECTED
List<Order> orders = new List<Order>();

foreach (var expectedItem in expected.Items)
{
    orders.Add(new Order
    {
        Id = expectedItem.Id,
    });
}

Then I setup my Mock like this.然后我像这样设置我的 Mock。

_finicityRepositoryMock.Setup(moq => moq.FindFirst(It.IsAny<Expression<Func<Order, bool>>>()))
            .Returns((Expression<Func<Order, bool>> expression) =>
            {
                var order = orders.AsQueryable().Where(expression).FirstOrDefault();

                if (order == null)
                {
                    return Task.FromResult((Order)null);
                }

                return Task.FromResult(
                    new Order
                    {
                        BorrowerID = order.Id
                    });
            });

You could analyze the Expression .您可以分析Expression

If you only do x => x.Id == "123" in the predicate expression, the solution could be as simple as:如果只在谓词表达式中执行x => x.Id == "123" ,则解决方案可能很简单:

mock.Setup(x => x.FindFirstOrDefault(It.IsAny<Expression<Func<Order, bool>>>()))
    .Returns<Expression<Func<Order, bool>>>(
        predicate =>
        {
            var id = (string)((ConstantExpression)(((BinaryExpression)predicate.Body).Right)).Value;
            return new Order { Id = id };
        });

If you also use other properties, then you need an ExpressionVisitor which helps you extract values for each property:如果您还使用其他属性,那么您需要一个ExpressionVisitor来帮助您提取每个属性的值:

class PredicatePropertyValueExpressionVisitor : ExpressionVisitor
{
    public Dictionary<string, object> PropertyValues { get; } = new Dictionary<string, object>();

    protected override Expression VisitBinary(BinaryExpression node)
    {
        if (node.Left is MemberExpression pe && pe.Member is PropertyInfo pi)
        {
            PropertyValues[pi.Name] = (node.Right as ConstantExpression).Value;
        }

        return base.VisitBinary(node);
    }
}

Then mock will be:然后模拟将是:

mock.Setup(x => x.FindFirstOrDefault(It.IsAny<Expression<Func<Order, bool>>>()))
    .Returns<Expression<Func<Order, bool>>>(
        predicate =>
        {
            var visitor = new PredicatePropertyValueExpressionVisitor();
            visitor.Visit(predicate);
            return new Order { Id = visitor.PropertyValues["Id"].ToString() };
        });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM