[英]Moq: Get parameter value of expression predicate
我是使用 Moq 的新手,我正在嘗試將值傳遞給 Moq'd 方法以在 Returns 方法中使用。
我正在成功地執行以下操作。
_repositoryMock.Setup(x => x.GetByOrderId(It.IsAny<string>()))
.Returns((string id) => Task.FromResult(
new Order
{
Id = id
}));
代碼中的用法:
var order = _repository.GetByOrderId("123");
以上工作正常,傳遞給 Returns 方法的id
與我在代碼中傳遞給 GetByOrderId 方法的 ID 相同。
但是,我想讓我的存儲庫更通用,所以我想將我的 GetByOrderId 更改為 FindFirstOrDefault,它采用表達式謂詞而不是 ID。
用法如下:
var order = _repository.FindFirstOrDefault( o => x.Id == "123");
單元測試更改為:
_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?
}));
那么我怎樣才能獲得那個ID呢? “123”。 有什么辦法嗎?
我找到了解決辦法。
我只是設置了一個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,
});
}
然后我像這樣設置我的 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
});
});
您可以分析Expression
。
如果只在謂詞表達式中執行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 };
});
如果您還使用其他屬性,那么您需要一個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);
}
}
然后模擬將是:
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.