Could someone explain to me, why this doesn't work?
builder.Setup(b => b.BuildCommand(query ?? It.IsAny<string>())).Returns(command);
If query is null, BuildCommand will be passed null, and not It.IsAny<string>()
Instead, I have to do this:
if(query == null)
builder.Setup(b => b.BuildCommand(It.IsAny<string>())).Returns(command);
else
builder.Setup(b => b.BuildCommand(query)).Returns(command);
Is it related to the delegate?
EDIT - Complete example
public static void ReturnFromBuildCommand(this Mock<IQueryCommandBuilder> builder, IQueryCommand command, string query = null)
{
if(query == null)
builder.Setup(b => b.BuildCommand(It.IsAny<string>())).Returns(command);
else
builder.Setup(b => b.BuildCommand(query)).Returns(command);
}
Then I can call it like
var command = new Mock<IQueryCommand>();
var builder = new Mock<IQueryCommandBuilder>();
builder.ReturnFromBuildCommand(command.Object);
Or
string query = "SELECT Name FROM Persons;";
builder.ReturnFromBuildCommand(command.Object, query);
Depending on whether I care about the parameter or not.
The Setup method of the mock takes in an expression, which the Moq framework then deconstructs to determine the method being called and the arguments to it. It then sets up an interceptor to match the arguments.
You can see this in the Mock source:
internal static MethodCallReturn<T, TResult> Setup<T, TResult>(
Mock<T> mock,
Expression<Func<T, TResult>> expression,
Condition condition)
where T : class
{
return PexProtector.Invoke(() =>
{
if (expression.IsProperty())
{
return SetupGet(mock, expression, condition);
}
var methodCall = expression.GetCallInfo(mock);
var method = methodCall.Method;
var args = methodCall.Arguments.ToArray();
ThrowIfNotMember(expression, method);
ThrowIfCantOverride(expression, method);
var call = new MethodCallReturn<T, TResult>(mock, condition, expression, method, args);
var targetInterceptor = GetInterceptor(methodCall.Object, mock);
targetInterceptor.AddCall(call, SetupKind.Other);
return call;
});
}
Here args is of type Expression[].
(reference: https://github.com/moq/moq4/blob/master/Source/Mock.cs#L463)
This args array is passed into the constructor for the Moq type MethodCallReturn as the parameter arguments. That constructor (via the base class MethodCall) generates an argument matcher using MatcherFactory.Create. (reference: https://github.com/moq/moq4/blob/master/Source/MethodCall.cs#L148)
This is where things start to get interesting!
In the MatcherFactory.Create method, it tries to determine the type of the argument's Expression by looking that the Expression.NodeType and/or checking it against known types, such as MatchExpression (which is what something like Is.Any<string>() would be).
(reference: https://github.com/moq/moq4/blob/master/Source/MatcherFactory.cs#L54)
So let's take a step back. In your specific case, the code query ?? Is.Any<string>() is compiled down to an expression itself -- something like this ugly mess (as generated by the dotPeek decompiler):
(Expression) Expression.Coalesce((Expression) Expression.Field((Expression) Expression.Constant((object) cDisplayClass00, typeof (Extension.\u003C\u003Ec__DisplayClass0_0)),
FieldInfo.GetFieldFromHandle(__fieldref (Extension.\u003C\u003Ec__DisplayClass0_0.query))),
(Expression) Expression.Call((Expression) null, (MethodInfo) MethodBase.GetMethodFromHandle(__methodref (It.IsAny)), new Expression[0]))
And that's what the first argument looks like. You can rewrite your code to better express what Moq sees, like this:
public static void ReturnFromBuildCommand(this Mock<IQueryCommandBuilder> builder, IQueryCommand command, string query = null)
{
Expression<Func<IQueryCommandBuilder, IQueryCommand>> expressOfFunc = commandBuilder => (commandBuilder.BuildCommand(query ?? It.IsAny<string>()));
var methodCall = expressOfFunc.Body as MethodCallExpression;
var args = methodCall.Arguments.ToArray();
var nodeType = args[0].NodeType;
builder.Setup(expressOfFunc)
.Returns(command);
}
If you place a breakpoint, you can see that the value of nodeType is Coalesce. Now, go back and change it to just use query, and nodeType becomes MemberAccess. Use It.IsAny<string>(), and nodeType is Call.
This explains the differences between the three approaches and why it's not acting like you expected. As for why it triggers on null is not clear to me, to be honest, but whatever matcher comes out of MatcherFactory.CreateMatcher seems to think null is a valid value for your mock configuration.
Related
I'm using a combination of reflection and expression trees, and want to pass back certain property accessors from a class to a calling method. My current code has a method traversing the class and returning a list of MemberExpressions. The caller then iterates over the member expressions and creates lambdas, which should then be called with an instance of the inspected class to return the value of the property.
Here is a sample of what it would look like without the method calls (Runnable in LINQPad):
void Main()
{
var t = new Test { Prop = "Test" };
var property = t.GetType().GetProperty("Prop");
var baseType = Expression.Parameter(typeof(Test), "baseType");
var memberAccess = Expression.MakeMemberAccess(baseType, property);
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));
var func = lambda.Compile();
var result = func(t);
result.Dump();
}
class Test {
public string Prop { get; set; }
}
This does not work, throwing this exception:
InvalidOperationException: variable 'baseType' of type 'UserQuery+Test' referenced from scope '', but it is not defined
However, if I change the creation of the lambda to this:
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, baseType);
That is, replace the Expression.Parameter with the variable used earlier, then it works. This is not (easily) possible in the scenario where I want to use it, since I would have to return the original parameter along with the list (I could return a tuple, of course, but I would prefer not to, if it is not necessary).
Why does it work like this? Inspecting the DebugView of the lambda, they are exactly the same no matter what approach is used:
.Lambda #Lambda1<System.Func`2[UserQuery+Test,System.String]>(UserQuery+Test $baseType)
{
$baseType.S
}
Yes, you need to refer ParameterExpression, used earlier. This won't compile too:
private String Foo(Test myParam)
{
return myAnotherParam.MyProperty;
}
With instatiating new ParameterExpression in lambda, you're doing the same thing (but note, when making lambda, you're doing it in reversed order - first, you're constructing a method body, then - a method declaration):
// return myAnotherParam.MyProperty;
var baseType = Expression.Parameter(typeof(Test), "baseType");
var memberAccess = Expression.MakeMemberAccess(baseType, property);
// private String Foo(MyClass myParam)
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));
The following code is a helper I've created for a system which allows administrators to create their own queries on a database. It returns a lambda expression based on the method and value provided.
I am attempting to find a way to pass parameters to the method call - in this example I am using the StartsWith parameter of String, and attempting to set StringComparison.OrdinalIgnoreCase as a parameter.
There will be others parameters required too, depending on the type of the property specified. I'm hoping that understanding the method of supplying the string comparison property will enable me to add the rest later.
The underlying code works correctly, I just need it to be case-insensitive.
I have used this question as a guide, but the solution does not seem applicable here.
Here is the code:
public static class LambdaExpressionHelper<T> {
public static Expression<Func<T, bool>> Build(string propertyName, string method, string propertyValue) {
PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
ParameterExpression e = Expression.Parameter(typeof(T), "e");
MemberExpression m = Expression.MakeMemberAccess(e, propertyInfo);
ConstantExpression c = Expression.Constant(propertyValue, m.Type);
MethodInfo mi = m.Type.GetMethod(method, new Type[] { m.Type }, );
// The below caused errors
//object classInstance = Activator.CreateInstance(typeof(T), null);
//object[] paramArray = new object[] { StringComparison.OrdinalIgnoreCase };
//mi.Invoke(classInstance, paramArray);
Expression call = Expression.Call(m, mi, c);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, e);
return lambda;
}
}
// External code:
var lambda = LambdaExpressionHelper<MailingListMember>.Build("EmailAddress", "StartsWith", "RoRy#");
Thanks for any help.
In the general case this should work:
public static Expression<Func<T, bool>>
Build(string propertyName, string method, params object[] args)
{
var propertyInfo = typeof(T).GetProperty(propertyName);
var e = Expression.Parameter(typeof(T), "e");
var m = Expression.MakeMemberAccess(e, propertyInfo);
var mi = m.Type.GetMethod(method, args.Select(a => a.GetType()).ToArray());
var c = args.Select(a => Expression.Constant(a, a.GetType())).ToArray();
Expression call = Expression.Call(m, mi, c);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(call, e);
return lambda;
}
The idea is that you accept any number of constant arguments, and use their types to select the appropriate overload when calling GetMethod. After that, you create the appropriate number of constant expressions from those arguments to pass to Expression.Call.
So with the above code, you could do:
var l1 = LambdaExpressionHelper<MailingListMember>.Build(
"EmailAddress", "StartsWith", "RoRy#");
var l2 = LambdaExpressionHelper<MailingListMember>.Build(
"EmailAddress", "StartsWith", "RoRy#", StringComparison.OrdinalIgnoreCase);
If you also need to get the value StringComparison.OrdinalIgnoreCase from the string "StringComparison.OrdinalIgnoreCase", I would factor this out into a separate method so that the interface of Build can remain generic. Exactly how to do it is covered in Getting Enum value via reflection (and I guess in lots of similar questions as well).
Note: I don't have convenient access to a compiler right now, so please excuse any mistakes.
I'm not sure i understand your question exactly, but hopefully this will help you on the way.
If you are using .NET 4.0 you can use the new keyword "dynamic" for much easier reflection code:
dynamic myDynamicObj = "Hello World!"; // or Activator.CreateInstance...
var doesIndeed = myDynamicObj.StartsWith("Hello", StringComparison.OrdinalIgnoreCase);
This does evaluate at run time so make sure spelling/case etc is correct.
Edit:
Assuming you always wanted to call methods with one String-arg returning bool, a possible solution would be to create a delegate type -
delegate bool CompareString(String str);
and than have the second argument of Build as that type:
Build(String .., CompareString cs, String ...)
But this does not work if you need to add extra arguments, as in the second arg of type StringComparison. A if/switch could be the answer there though, i.e if(CompareString is StartsWith)...
Sorry, not at a windows-computer so i can't test further.
Method M takes 2 parameters, P1 and P2. P2 is a delegate. I want to tell a mock object, "Whenever method M is called with parameter P1, invoke P2 and pass object O to it." I'm using Moq.
The following approach works, but seems a bit verbose.
this.DataCacheMock = Mock.Of<IDataCache>();
var dataObject = new DataObject();
Mock.Get(this.DataCacheMock)
.Setup(m => m.GetDataObject(123, It.IsAny<EventHandler<DataPortalResult<DataObject>>>()))
.Callback((int id, EventHandler<DataPortalResult<DataObject>> callback) => callback(null, new DataPortalResult(dataObject, null, null)));
I'd like to refactor that last bit into a generic helper method so that I (and future test authors) would only need to write something like this:
TestTools.ArrangeDataPortalResult(this.DataCacheMock.GetDataObject, 123, dataObject);
The big question is: what would go inside that helper method? I've had partial success so far, but I'm wondering if there's any way to get all the way there.
First Attempt (doesn't work)
public static void ArrangeDataPortalResult<TMock, TResult, TParam>(
TMock mockObject,
Action<TMock, TParam, EventHandler<DataPortalResult<TResult>>> action,
TParam parameter,
TResult result)
where TMock : class
{
Moq.Mock.Get(mockObject)
.Setup(m => action(m, parameter, Moq.It.IsAny<EventHandler<DataPortalResult<TResult>>>()))
.Callback<TParam, EventHandler<DataPortalResult<TResult>>>((p, callback) =>
callback(null, new DataPortalResult<TResult>(result, null, null)));
}
I can call this method like so:
TestTools.ArrangeDataPortalResult<IDataCache, DataObject, int>(
this.DataCacheMock,
(mock, param, handler) => mock.GetDataObject(param, handler),
dataObjectId,
dataObject);
As it turns out, Moq doesn't like what I'm passing to the Setup method. It throws an exception, saying "Expression is not a method invocation".
Second Attempt
In this approach I do some manipulation of LINQ expressions (which I've never done before).
public static void ArrangeDataPortalResult<TMock, TParam, TResult>(
TMock mockObject,
Expression<Action<TMock>> methodCall, TResult result)
where TMock : class
{
// Get the method that will be called on the mock object, and the method's parameters.
var methodCallExpression = methodCall.Body as MethodCallExpression;
var parameters = methodCallExpression.Arguments;
// Create a new parameter list, and substitute Moq.It.IsAny<EventHandler<DataPortalResult<TResult>>>() for the callback.
// This is so that the test author doesn't need to write It.IsAny<blah>.
var newParameters = parameters.Select(p => p).ToList();
newParameters.RemoveAt(newParameters.Count - 1);
var isAny = typeof(Moq.It).GetMethod("IsAny").MakeGenericMethod(typeof(EventHandler<DataPortalResult<TResult>>));
var newCallbackParameterExpression = Expression.Call(null, isAny);
newParameters.Add(newCallbackParameterExpression);
// Create a new expression that contains the new IsAny parameter.
var newMethodCallExpression = Expression.Call(methodCallExpression.Object, methodCallExpression.Method, newParameters);
// Set up the mock object to expect a method call with the same parameters passed to it, but allow any callback to be passed to it.
// Additionally, tell the mock object to immediately invoke its callback, and pass the given result to it.
Moq.Mock.Get(mockObject)
.Setup(Expression.Lambda<Action<TMock>>(newMethodCallExpression, methodCall.Parameters))
.Callback<TParam, EventHandler<DataPortalResult<TResult>>>((p, callback) => callback(null, new DataPortalResult<TResult>(result, null, null)));
}
This method can be called like so.
TestTools.ArrangeDataPortalResult<IDataCache, int, DataObject>(
this.DataCacheMock,
mock => mock.GetDataObject(123, null),
dataObject);
This works, and I might settle for something like this if necessary. Unfortunately if I were to accidentally call the wrong method of DataCacheMock (maybe it has an overload that takes a string instead of an int), then I would get a run time error rather than a compile time error.
Third Attempt
public static void ArrangeDataPortalResultMoq<TMock, TParam, TResult>(
Expression<Action> methodCall, TResult result)
where TMock : class
{
// Get the method that will be called on the mock object, and the method's parameters.
// (This part is the same.)
// Create a new parameter list, and substitute Moq.It.IsAny<EventHandler<DataPortalResult<TResult>>>() for the callback.
// (This part is the same.)
// Create a new expression that contains the new IsAny parameter.
var newMethodCallExpression = Expression.Call(Expression.Parameter(typeof(TMock), "mock"), methodCallExpression.Method, newParameters);
// Get the real mock object referred to in the method call.
var mockObject = Expression.Lambda<Func<TMock>>(methodCallExpression.Object).Compile()();
// Set up the mock object to expect a method call with the same parameters passed to it, but allow any callback to be passed to it.
// Additionally, tell the mock object to immediately invoke its callback, and pass the given result to it.
Moq.Mock.Get(mockObject)
.Setup(Expression.Lambda<Action<TMock>>(newMethodCallExpression, Expression.Parameter(typeof(TMock), "mock")))
.Callback<TParam, EventHandler<DataPortalResult<TResult>>>((p, callback) => callback(null, new DataPortalResult<TResult>(result, null, null)));
}
This version gets the mock object from the expression you pass to it, so you don't have to mention the mock object twice when you call the helper method:
TestTools.ArrangeDataPortalResultMoq<IDataCache, int, ceQryUomsBO>(
() => this.DataCacheMock.GetDataObject(dataObjectId, null),
dataObject);
This approach still has the same problem with types though.
I (and future test authors) could probably deal with the verbose syntax mentioned at the top, and we could probably deal with the lesser type safety since the test would just fail. I'd still like to see if this is possible with Moq though; I've gone this far down the rabbit hole. :-)
In case it helps someone else, I ended up with a solution that allows me to do this:
TestTools.ArrangeDataPortalResult(
this.DataCacheMock,
(param1, callback) => this.DataCacheMock.Object.GetDataObject(param1, callback),
123,
dataObject);
This was good enough for me. My solution is below.
public static void ArrangeDataPortalResult<TMocked, TResult, TParam>(Mock<TMocked> mock, Expression<Action<TParam, EventHandler<DataPortalResult<TResult>>>> expectedMethodCall, TParam parameter, TResult result)
where TMocked : class
{
var methodCallExpr = expectedMethodCall.Body as MethodCallExpression;
var newMethodCallExpr = TransformAsyncCallForMoq<TMocked, TResult>(methodCallExpr, parameter);
mock.Setup(newMethodCallExpr)
.Callback<TParam, EventHandler<DataPortalResult<TResult>>>((p, callback) => callback(null, new DataPortalResult<TResult>(result, null, null)));
}
private static Expression<Action<TMocked>> TransformAsyncCallForMoq<TMocked, TResult>(MethodCallExpression methodCallExpr, params object[] expectedParameterValues)
{
var methodCallParameters = methodCallExpr.Arguments;
/// Transform a method call on a specific object,
/// e.g. (param1, param2, callback) => MyMockObject.GetData(param1, param2, callback),
/// into a lambda expression that Moq's Setup method can use, which looks more like this:
/// m => m.GetData(5, "asdf", /* any event handler */).
MethodCallExpression newMethodCallExpression = Expression.Call(
Expression.Parameter(typeof(TMocked), "m"),
methodCallExpr.Method,
CreateParameterExpressionsWithAnyCallback(methodCallParameters, expectedParameterValues));
return Expression.Lambda<Action<TMocked>>(newMethodCallExpression, Expression.Parameter(typeof(TMocked), "m"));
}
private static IEnumerable<Expression> CreateParameterExpressionsWithAnyCallback(IEnumerable<Expression> oldParameterExpressions, IEnumerable<object> expectedParameterValues)
{
// Given a set of expressions and expected values, returns a new set of expressions that will
// allow Moq to set the proper method call expectation. Assumes there will be one more parameter
// expression (the callback parameter) that has no expected value, and allows any value for it.
var newParameterExpressions = oldParameterExpressions.Zip(expectedParameterValues,
(paramExpr, paramVal) => Expression.Constant(paramVal, paramExpr.Type) as Expression);
foreach (var expr in newParameterExpressions)
{
yield return expr;
}
var callbackParamExpr = oldParameterExpressions.Last();
var isAny = typeof(Moq.It).GetMethod("IsAny").MakeGenericMethod(callbackParamExpr.Type);
yield return Expression.Call(null, isAny) as Expression;
}
If anyone knows a simpler way to do it, I hope you'll share. :-)
I am trying to serialize something based upon meeting particular criteria.
To this end my original hope was to use attributes containing a lambda expression on an object's properties.
However, as this cannot be done I've settled for having a Func<T,bool> member within the class and passing the type (or first parameter type) and name of this Func through the property attribute. E.g.:
Func<SomeObject, bool> func = (p => p.Value == 4);
[FuncAtt(typeof(SomeObject), "func")]
public SomeObject PropertyName { get; set;}
In my serializer I need to call this Func<T, bool>.
Let's assume I have a Type t which is equal to typeof(SomeObject) in this case, or more abstractly, typeof(T). I can also get the Func<T,bool> itself, but only through reflection as an object.
My naive approach is something along these lines:
object func = typeof(MyClass).GetField(attribute.FuncName).GetValue(MyClassInstance);
Type funcType = typeof(Func<,>).MakeGenericType(attribute.Type, typeof(bool));
ParameterExpression p = Expression.Parameter(attribute.Type, objectToSerialize);
LambdaExpression l = Expression.Lambda(funcType, func, p); /* Won't work */
But this leads to the problem of casting a lambda to a delegate which is apparently erroneous.
I tried this in place of 'func':
(Expression)((Action)(() => func))
But that relies on func being a method call not a lambda.
So, can anyone point me in the right direction?
You can just do something like this, without need for expressions:
public static class Test
{
public static Predicate<int> func = s => s > 20;
}
and to get the value:
private void Form1_Load(object sender, EventArgs e)
{
var a = typeof(Test).GetField("func");
bool validates = ((Predicate<int>)a.GetValue(null)).Invoke(100);
}
edit to get the value without knowing the type:
bool validates = (bool)((Delegate)a.GetValue(null)).DynamicInvoke(100);
I think you can use Compile method of a lambda expression to cast it to a delegate.
here's what I found on MSDN:
The Expression<(Of <(TDelegate>)>)
type provides the Compile method,
that compiles the code represented by
the expression tree into an executable
delegate. This executable code is
equivalent to the executable code that
would have been generated had the
lambda expression been assigned to a
delegate type originally.
Here you can find it.
Not sure this is working sample, but this is the way:
// not sure what are you doing in this line, but assume it should return
// a method name specified in the attribute, e.g. "func" in your example.
// Also "func" must be a method (static one in my example) of SomeObject class
String funcname = typeof(MyClass).GetField(attribute.FuncName).GetValue(MyClassInstance);
ParameterExpression param = Expression.Parameter(typeof(SomeObject), "p");
MethodCallExpression call = Expression.Call(SomeObject, funcname, new Type[] { typeof(SomeObject), typeof(Boolean) }, param);
LambdaExpression lambda = Expression.Lambda<Func<SomeObject, Boolean>>(call, param);
now you can call the "func" method like this:
Boolean result = lambda.Compile()(SomeObjectInstance);
From my recent question, I try to centralize the domain model by including some silly logic in domain interface. However, I found some problem that need to include or exclude some properties from validating.
Basically, I can use expression tree like the following code. Nevertheless, I do not like it because I need to define local variable ("u") each time when I create lambda expression. Do you have any source code that is shorter than me? Moreover, I need some method to quickly access selected properties.
public void IncludeProperties<T>(params Expression<Func<IUser,object>>[] selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>
(
u => u.ID,
u => u.LogOnName,
u => u.HashedPassword
);
Thanks,
Lambdas are great for many scenarios - but if you don't want them, perhaps simply don't use them? I hate to say it, but simple strings are tried and tested, especially for scenarios like data binding. If you want fast access, you could look at HyperDescriptor, or there are ways of compiling a delegate to the property accessors, or you can build an Expression from the string and compile it (including a cast to object if you want a known signature, rather than calling the (much slower) DynamicInvoke).
Of course, in most cases even crude reflection is fast enough, and isn't the bottleneck.
I suggest starting with the simplest code, and check it is actually too slow before worrying about it being fast. If it isn't too slow, don't change it. Any of the above options would work otherwise.
Another thought; if you are using Expression, you could do something like:
public void IncludeProperties<T>(
Expression<Func<T,object>> selectedProperties)
{
// some logic to store parameter
}
IncludeProperties<IUser>( u => new { u.ID, u.LogOnName, u.HashedPassword });
and then take the expression apart? A bit tidier, at least... here's some sample code showing the deconstruction:
public static void IncludeProperties<T>(
Expression<Func<T, object>> selectedProperties)
{
NewExpression ne = selectedProperties.Body as NewExpression;
if (ne == null) throw new InvalidOperationException(
"Object constructor expected");
foreach (Expression arg in ne.Arguments)
{
MemberExpression me = arg as MemberExpression;
if (me == null || me.Expression != selectedProperties.Parameters[0])
throw new InvalidOperationException(
"Object constructor argument should be a direct member");
Console.WriteLine("Accessing: " + me.Member.Name);
}
}
static void Main()
{
IncludeProperties<IUser>(u => new { u.ID, u.LogOnName, u.HashedPassword });
}
Once you know the MemberInfos (me.Member in the above), building your own lambdas for individual access should be trivial. For example (including a cast to object to get a single signature):
var param = Expression.Parameter(typeof(T), "x");
var memberAccess = Expression.MakeMemberAccess(param, me.Member);
var body = Expression.Convert(memberAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, param);
var func = lambda.Compile();
Here's the shortest expression I can come up with:
public static void IncludeProperties(Expression<Action<IUser>> selectedProperties)
{
// some logic to store parameter
}
public static void S(params object[] props)
{
// dummy method to get to the params syntax
}
[Test]
public void ParamsTest()
{
IncludeProperties(u => S(
u.Id,
u.Name
));
}