我有一个非常奇怪的测试,我正在编写测试,如果发送电子邮件。我们使用hangfire所以我有一个包装器IHangfireWrapper,以便我可以模拟Enqueue方法。此Enqueue方法采用一个参数(Expression<Action<T>>
)。
因此,如果我想使用这种方法,它看起来就像这样。
_ServiceProvider.HangfireWrapper
.Enqueue<HangfireTasks>(x => x.SendEmail(subject, body, to));
我在传递主题,身体和到达的字符串。
所以这是棘手的部分。我想模仿这个电话,所以我可以看看主题,正文和字符串。
我有这个代码可以工作,我可以找回我想要的字符串,但它非常难看。
var hangfireMock = new Mock<IHangfireWrapper>();
string body = null;
string subject = null;
string to = null;
hangfireMock.Setup(x => x.Enqueue(It.IsAny<Expression<Action<HangfireTasks>>>()))
.Callback<Expression<Action<HangfireTasks>>>(expr =>
{
object parameters = ((ConstantExpression)((MemberExpression)((MethodCallExpression)expr.Body).Arguments[0]).Expression).Value;
body = (string)parameters.GetType().GetField("body").GetValue(parameters);
subject = (string)parameters.GetType().GetField("subject").GetValue(parameters);
to = (string)parameters.GetType().GetField("to").GetValue(parameters);
});
有更好/更短的方法吗? (这个代码甚至有意义吗?)
答案 0 :(得分:3)
你正在做的事情可能适用于你的编译器版本,只要你总是像那样形成lambda。
以下是一些不起作用的示例lambdas:
x => x.SendEmail("subject", "body", "to")
x => x.SendEmail(subject, subject, to)
你应该做的是取Arguments
调用SendEmail
并通过为它创建一个lambda表达式然后编译它来评估它们中的每一个:
var arguments = ((MethodCallExpression)expr.Body).Arguments;
subject = Expression.Lambda<Func<string>>(arguments[0]).Compile()();
body = Expression.Lambda<Func<string>>(arguments[1]).Compile()();
to = Expression.Lambda<Func<string>>(arguments[2]).Compile()();
编译表达式相对昂贵,因此解释表达式是有意义的。 You have that choice on .Net Core您可能还将在.Net Framework的未来版本中使用。