tags:

views:

446

answers:

2

I have a method on an interface that looks like this and I want to stub it with Rhino Mocks:

TValue GetPropertyOfExistingObject<TValue>(long id, Expression<Func<T, TValue>> propertyExpression);

My code that does the stubbing looks like this:

var service = MockRepository.GenerateStub<IQuoteService>();
service.Stub(s => s.GetPropertyOfExistingObject(1, q => q.QuoteNumber)).Return(1234);

Notice that one of the parameters in that method is an Expression<Func<T1, T2>>, and this stub is not returning the specified value. I know I can do this by using WhenCalled() but I was wondering if Stub() should work with expression parameters or if I'm just doing something wrong.

+1  A: 

I think the problem is related to how Expressions test equality. I just did a quick test in Snippet Compiler and my expressions never evaluated as the same:

 Expression<Func<int, string>> p = i => i.ToString();
 Expression<Func<int, string>> s = i => i.ToString();
 var b = p.Equals(s) || p == s;

(b was false for this test)

Probably in order for your test to work as is, you'd have to ignore the actual value of the second parameter (which may or may not be acceptable; If unacceptable I think you'll have to go the WhenCalled route).

Chris Shaffer
Your test proves why this doesn't work, but it seems that you should be able to determine if two expressions are equal if they each contain only one property and they reference the same property. Doesn't look like Rhino Mocks does that, but it would be nice if it did!
Jon Kruger
A: 

You can create a method that evaluates the equality between two expressions:

public class ExpressionMatcher
{
    public static Expression<Action<T>> Matches<T>(Expression<Action<T>> action)
    {
        var methodName = ((MethodCallExpression) action.Body).Method.Name;
        return Arg<Expression<Action<T>>>.Matches(a => ((MethodCallExpression)a.Body).Method.Name.Equals(methodName));
    }
}

Then change your stub statement to wrap the expression in a call to the expression matcher:

service.Stub(s => s.GetPropertyOfExistingObject(Arg<int>.Is.Equal(1), ExpressionMatcher.Matches<Quote>(q => q.QuoteNumber))).Return(1234);
This currently only works for methods in the expression, not properties. You would need to add property matching to the Expression Matcher. Also, if the method has arguments, you will need to compare those too.