[英]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.