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
-~----------~----~----~----~------~----~------~--~---