This is what I've come up with, it was an interesting experiment:
public static class MockRepositoryExtensions
    {
        public static void StubAndReturn<T, V>(this MockRepository mockery,
T input, V toReturn,
                                               Expression<Func<T, V>> expr)
        {
            var methods = GetMethods(expr).Reverse().ToArray();

            var mocks = new Dictionary<Type, object>{{typeof (T), input}};

            foreach (var method in methods.Take(methods.Count() - 1))
                if (!mocks.ContainsKey(method.ReturnType))
                    mocks.Add(method.ReturnType,
mockery.Stub(method.ReturnType));

            for (var i = 0; i < methods.Length; i++)
            {
                var methodArguments = methods[i].GetParameters().Select(p =>
p.DefaultValue);


 SetupResult.For(methods[i].Invoke(mocks[methods[i].DeclaringType],
                                                  methodArguments.Any() ?
new object[] {methodArguments} : null)).
                    IgnoreArguments()
                    .Return(i < methods.Length - 1 ?
mocks[methods[i].ReturnType] : toReturn);
            }
        }

        private static IEnumerable<MethodInfo> GetMethods<V,
T>(Expression<Func<T, V>> expr)
        {
            var body = expr.Body as MethodCallExpression;

            while (body != null)
            {
                yield return body.Method;
                body = Expression.Lambda<Action<IRepository>>(body.Object,
expr.Parameters).Body as MethodCallExpression;
            }
        }
    }

It allows me do do this:

[TestFixture]
public class CallChain
{
    [Test]
    public void Test()
    {
        var mockery = new MockRepository();

        var repository = mockery.Stub<IRepository>();
        var toReturn = new ArrayList();

        using (mockery.Record())
        {
            mockery.StubAndReturn(repository, toReturn, repo =>
repo.Find(null)

 .Order(null)

 .Group(null)
                                                                    .All());
        }
        using (mockery.Playback())
        {
            var returnedItems = repository.Find(null)
                .Order(null)
                .Group(null)
                .All();

            Assert.That(returnedItems, Is.EqualTo(toReturn));
        }
    }
}


On Thu, Sep 25, 2008 at 1:31 PM, Vladan <[EMAIL PROTECTED]> wrote:

>
> My idea is to provide a chain and a result to attach at the end of the
> chain and have lambda inspector go over the chain and connect the dots
> (mock them).
>
> Automocking container will not work I think because these are not
> dependencies, but chaining... although IMO each of them could end in
> the container and be accessible (additional benefit, but not needed
> for me at this point).
>
> My current idea is something like this:
>
> EntityRepositoryMocker.SetupMock(repo =>
> repo.Find(byCriteria).Order(byOrder).Group(byGroup).All())
>                                   .On(customerRepository.Find(byCriteria))
>
> .Return(someObjectWhichShouldBeOfSameTypeAsTheLastMethodInChainWhichReturnsIt)
>
>
> The end object of "AttachTo" is IMethodOptions, so the "Return" part
> is actually Rhino part which is then flexible enough to add
> constraints and such further on on the last method in chain.
>
> Besides this, if everything goes ok, you would also have instead of
> SetupMock, a SetupExpectation which would work in exact same way
> except it would do instead of SetupResult.For, an Expect.Call.
>
> Ill start cracking at it now, keep your fingers crossed that it
> works :)
>
>
>
> Btw. For the generalise approach... if I have a Lambda Inspector and a
> Mocker which mocks and chains the result of Inspector, basically the
> solution is already generalised for any kind of fluent interface
> mocking.
>
>
>
> Vladan
>
> On Sep 25, 12:56 pm, "Simone Busoli" <[EMAIL PROTECTED]> wrote:
> > Good. One question, how do you generalize this approach? I mean, you call
> > chain involves stuff you need to mock - actually, stub - and a final
> return
> > type. I dealt with it leaving the last call out of the loop and handling
> it
> > by hand. I'd like to see what you come up with in the end. BTW, seems a
> good
> > usage of the auto mocking container.
> >
> > On Thu, Sep 25, 2008 at 12:52 PM, Vladan <[EMAIL PROTECTED]> wrote:
> >
> > > .Invoke ..... aaaaargh, it was right in front of me and I forgot about
> > > it... thnx so much for the idea! it should work perfectly now.
> >
> > > Ill try it out tonight and let you know.
> >
> > > Vladan
> >
> > > On Sep 23, 4:58 pm, "Simone Busoli" <[EMAIL PROTECTED]> wrote:
> > > > Here's what I've come up with, I'm not sure what are you trying to do
> > > > exactly.
> > > > [TestFixture]
> > > > public class CallChain
> > > > {
> > > >     [Test]
> > > >     public void Test()
> > > >     {
> > > >         var mockery = new MockRepository();
> >
> > > >         var repository = mockery.DynamicMock<IRepository>();
> > > >         var findMock = mockery.DynamicMock<IFindQueryPart>();
> > > >         var orderMock = mockery.DynamicMock<IOrderQueryPart>();
> > > >         var groupMock = mockery.DynamicMock<IGroupQueryPart>();
> > > >         var returnedItemsStub = new ArrayList();
> >
> > > >         var mocks = new object[] { groupMock, orderMock, findMock,
> > > > repository };
> >
> > > >         var methods = MethodsFromLambda(repo => repo.Find(null)
> > > >                                                  .Order(null)
> > > >                                                  .Group(null)
> > > >                                                  .All()).ToList();
> >
> > > >         using (mockery.Record())
> > > >         {
> > > >             for (var i = methods.Count - 1; i > 0; i--)
> > > >                 SetupResult.For(methods[i].Invoke(mocks[i], new
> object[]
> > > > {null}))
> > > >                     .IgnoreArguments()
> > > >                     .Return(mocks[i - 1]);
> >
> > > >             SetupResult.For(methods[0].Invoke(groupMock,
> > > > null)).IgnoreArguments().Return(returnedItemsStub);
> > > >         }
> > > >         using (mockery.Playback())
> > > >         {
> > > >             var returnedItems = repository.Find(null)
> > > >                 .Order(null)
> > > >                 .Group(null)
> > > >                 .All();
> >
> > > >             Assert.That(returnedItems,
> Is.EqualTo(returnedItemsStub));
> > > >         }
> > > >     }
> >
> > > >     private static IEnumerable<MethodInfo>
> > > > MethodsFromLambda(Expression<Action<IRepository>> expr)
> > > >     {
> > > >         var body = expr.Body as MethodCallExpression;
> >
> > > >         while (body != null)
> > > >         {
> > > >             yield return body.Method;
> > > >             body =
> Expression.Lambda<Action<IRepository>>(body.Object,
> > > > expr.Parameters).Body as MethodCallExpression;
> > > >         }
> > > >     }
> >
> > > > }
> >
> > > > public interface IRepository
> > > > {
> > > >     IFindQueryPart Find(object o);
> >
> > > > }
> >
> > > > public interface IFindQueryPart
> > > > {
> > > >     IOrderQueryPart Order(object order);
> >
> > > > }
> >
> > > > public interface IOrderQueryPart
> > > > {
> > > >     IGroupQueryPart Group(object projection_for_group);
> >
> > > > }
> >
> > > > public interface IGroupQueryPart
> > > > {
> > > >     ArrayList All();
> >
> > > > }
> > > > On Tue, Sep 23, 2008 at 9:03 AM, Vladan <[EMAIL PROTECTED]> wrote:
> >
> > > > > no one?
> >
> > > > > On Sep 22, 10:50 am, Vladan <[EMAIL PROTECTED]> wrote:
> > > > > > Actually sorry, I've expressed something wrong...
> >
> > > > > > from MethodInfo I get the type that needs to be mocked... so I
> can
> > > > > > easily create the mock itself:
> >
> > > > > > var mock = mocks.DynamicMock(methodInfo.ReturnType);
> >
> > > > > > ... now how can I assign this?
> >
> > > > > > From methodInfo I have a method to which this mock needs to be
> > > > > > assigned to (methodInfo.Name), if I could only do this:
> >
> > > > > > SetupResult.For(findMethodInfo).Return(findMethodReturnTypeMock);
> >
> > > > > > On Sep 22, 10:39 am, Vladan <[EMAIL PROTECTED]> wrote:
> >
> > > > > > > I have a bit of a strange situation.
> >
> > > > > > > I have an Repository implementation which is based on a fluent
> > > > > > > interface for defining a Find query, it looks something like
> this:
> >
> > > > > > > var returnedItems = repository.Find(some_ICriteria)
> > > > > > >                                            .Order(some_Order)
> >
> > > > >  .Group(some_Projection_for_group)
> > > > > > >                                            .All()
> >
> > > > > > > Now, when testing this I need to write for example for
> SetupResult
> > > the
> > > > > > > following tedious code:
> >
> > > > > > > var findMock = mocks.DynamicMock<FindQueryPart>();
> > > > > > > var orderMock = mocks.DynamicMock<OrderQueryPart>();
> > > > > > > var groupMock = mocks.DynamicMock<GroupQueryPart>();
> > > > > > > var returnedItems = new List();
> >
> > > > > > >
> SetupResult.For(repository.Find(some_ICriteria)).Return(findMock);
> > > > > > > SetupResult.For(findMock.Order(some_Order)).Return(orderMock);
> >
> > >
> SetupResult.For(orderMock.Group(some_Projection_for_group)).Return(groupMock);
> > > > > > > SetupResult.For(groupMock.All()).Return(returnedItems);
> >
> > > > > > > As you can imagine, for a single query call this is alot of
> code,
> > > and
> > > > > > > somehow I feel it smells (I need this amount of code because
> each
> > > step
> > > > > > > in the fluent interface above returns a different object via
> > > interface
> > > > > > > (e.g. IFindQueryPart).
> >
> > > > > > > One important thing is that the SetupResult must chain the
> methods
> > > in
> > > > > > > exactly the way they've been chained in the call (for example
> Order
> > > > > > > must be chained to Group and not vice versa).
> >
> > > > > > > Now to aid this, I've written a Lambda expression inspector
> (simple
> > > > > > > stuff) which call looks like this:
> >
> > > > > > > MockFromLambda(repository => repository.Find(some_ICriteria)
> >
> > > > >  .Order(some_Order)
> >
> > > > >  .Group(some_Projection_for_group)
> >
> > >  .All());
> >
> > > > > > > And it is able to return to me a MethodInfo object for each
> call in
> > > > > > > the chain (Find call, Order call, Group call and All call).
> >
> > > > > > > My question is now... how can I generate a DynamicMock from the
> > > > > > > information in that MethodInfo? and after that feed that to the
> > > > > > > SetupResult?
> >
> > > > > > > The idea would be to dynamically generate the chain of mocks
> from
> > > the
> > > > > > > Lambda expression and chain them all together?
> >
> > > > > > > Any ideas anyone? Has anyone tried this before?
> >
> > > > > > > Thanks,
> > > > > > > Vladan
> >
>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Rhino Tools Dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/rhino-tools-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to