我有一个使用此方法的存储库
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
我有一个方法正在使用它来让用户使用
var user = this.applicationUserRepository.Get(x => x.EmailAddress == userName).FirstOrDefault();
然后在方法中使用不同的表达式调用相同的方法,如下所示,以检查处理第一个用户的用户
var changingUser = this.applicationUserRepository.Get(x => x.Id == changingUserId).FirstOrDefault();
我试图用两个设置来模拟存储库,在同一个测试中调用它两次。
string emailAddress = "myaddresss@test.com";
int changingUserId = 5;
var targetUsers = new List<ApplicationUser>
{
new ApplicationUser { Id = 1, Password = "Testing123", EmailAddress = emailAddress }
};
// Setup the user that will be modified to be found
var mockApplicationUserRepository = new Mock<IRepository<ApplicationUser>>();
mockApplicationUserRepository
.Setup(aur => aur.Get(x => x.EmailAddress == userName, null, string.Empty))
.Returns(targetUsers.AsEnumerable());
// Set up to query the changing user to not be found
mockApplicationUserRepository
.Setup(aur2 => aur2.Get(x => x.Id == changingUserId, null, string.Empty))
.Returns(new List<ApplicationUser>().AsEnumerable()); // Empty list
即使第二次通话永远不会被击中,对于这个测试,我想学习如何设置它。 当我运行测试时,第一次调用
var user = this.applicationUserRepository.Get(x => x.EmailAddress == userName).FirstOrDefault();
我得到了空
如果我将模拟更改为
It.IsAny<Expression<Func<ApplicationUser, bool>>>()
我得到了预期的用户。
我无法弄清楚如何设置两个调用,以便知道要使用哪个表达式。任何帮助将不胜感激。
答案 0 :(得分:2)
问题是Moq没有比较你使用的表达式(只有引用相等)。
public static class LambdaCompare
{
public static bool Eq<TSource, TValue>(
Expression<Func<TSource, TValue>> x,
Expression<Func<TSource, TValue>> y)
{
return ExpressionsEqual(x, y, null, null);
}
public static Expression<Func<Expression<Func<TSource, TValue>>, bool>> Eq<TSource, TValue>(Expression<Func<TSource, TValue>> y)
{
return x => ExpressionsEqual(x, y, null, null);
}
private static bool ExpressionsEqual(Expression x, Expression y, LambdaExpression rootX, LambdaExpression rootY)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
var valueX = TryCalculateConstant(x);
var valueY = TryCalculateConstant(y);
if (valueX.IsDefined && valueY.IsDefined)
return ValuesEqual(valueX.Value, valueY.Value);
if (x.NodeType != y.NodeType
|| x.Type != y.Type) return false;
if (x is LambdaExpression)
{
var lx = (LambdaExpression) x;
var ly = (LambdaExpression) y;
var paramsX = lx.Parameters;
var paramsY = ly.Parameters;
return CollectionsEqual(paramsX, paramsY, lx, ly) && ExpressionsEqual(lx.Body, ly.Body, lx, ly);
}
if (x is MemberExpression)
{
var mex = (MemberExpression) x;
var mey = (MemberExpression) y;
return Equals(mex.Member, mey.Member) && ExpressionsEqual(mex.Expression, mey.Expression, rootX, rootY);
}
if (x is BinaryExpression)
{
var bx = (BinaryExpression) x;
var by = (BinaryExpression) y;
return bx.Method == @by.Method && ExpressionsEqual(bx.Left, @by.Left, rootX, rootY) &&
ExpressionsEqual(bx.Right, @by.Right, rootX, rootY);
}
if (x is ParameterExpression)
{
var px = (ParameterExpression) x;
var py = (ParameterExpression) y;
return rootX.Parameters.IndexOf(px) == rootY.Parameters.IndexOf(py);
}
if (x is MethodCallExpression)
{
var cx = (MethodCallExpression)x;
var cy = (MethodCallExpression)y;
return cx.Method == cy.Method
&& ExpressionsEqual(cx.Object, cy.Object, rootX, rootY)
&& CollectionsEqual(cx.Arguments, cy.Arguments, rootX, rootY);
}
throw new NotImplementedException(x.ToString());
}
private static bool ValuesEqual(object x, object y)
{
if (ReferenceEquals(x, y))
return true;
if (x is ICollection && y is ICollection)
return CollectionsEqual((ICollection) x, (ICollection) y);
return Equals(x, y);
}
private static ConstantValue TryCalculateConstant(Expression e)
{
if (e is ConstantExpression)
return new ConstantValue(true, ((ConstantExpression) e).Value);
if (e is MemberExpression)
{
var me = (MemberExpression) e;
var parentValue = TryCalculateConstant(me.Expression);
if (parentValue.IsDefined)
{
var result =
me.Member is FieldInfo
? ((FieldInfo) me.Member).GetValue(parentValue.Value)
: ((PropertyInfo) me.Member).GetValue(parentValue.Value);
return new ConstantValue(true, result);
}
}
if (e is NewArrayExpression)
{
var ae = ((NewArrayExpression) e);
var result = ae.Expressions.Select(TryCalculateConstant);
if (result.All(i => i.IsDefined))
return new ConstantValue(true, result.Select(i => i.Value).ToArray());
}
return default(ConstantValue);
}
private static bool CollectionsEqual(IEnumerable<Expression> x, IEnumerable<Expression> y, LambdaExpression rootX, LambdaExpression rootY)
{
return x.Count() == y.Count()
&& x.Select((e, i) => new {Expr = e, Index = i})
.Join(y.Select((e, i) => new { Expr = e, Index = i }),
o => o.Index, o => o.Index, (xe, ye) => new { X = xe.Expr, Y = ye.Expr })
.All(o => ExpressionsEqual(o.X, o.Y, rootX, rootY));
}
private static bool CollectionsEqual(ICollection x, ICollection y)
{
return x.Count == y.Count
&& x.Cast<object>().Select((e, i) => new { Expr = e, Index = i })
.Join(y.Cast<object>().Select((e, i) => new { Expr = e, Index = i }),
o => o.Index, o => o.Index, (xe, ye) => new { X = xe.Expr, Y = ye.Expr })
.All(o => Equals(o.X, o.Y));
}
private struct ConstantValue
{
public ConstantValue(bool isDefined, object value) : this()
{
IsDefined = isDefined;
Value = value;
}
public bool IsDefined { get; private set; }
public object Value { get; private set; }
}
}
你可以这样设置你的模拟:
Expression<Func<ApplicationUser, bool>> expr = x => x.EmailAddress == emailAddress;
var mockApplicationUserRepository = new Mock<IRepository<ApplicationUser>>();
mockApplicationUserRepository
.Setup(aur => aur.Get(It.Is<Expression<Func<ApplicationUser, bool>>>(x => LambdaCompare.Eq(x, expr)), null, string.Empty))
.Returns(targetUsers.AsEnumerable());
答案 1 :(得分:0)
只需在这个旧答案中添加评论(虽然非常有用的代码)
此版本的 LambdaCompare 类缺少比较 UnaryExpression 的案例,这是原始帖子中的代码中包含的内容。
使用该代码代替此代码(我学到了很多东西......)