Mocking delegates

386 views
Skip to first unread message

Drew Noakes

unread,
May 13, 2009, 9:11:31 AM5/13/09
to Moq Discussions, D.No...@mwam.com
I searched the discussion archives for this and was surprised not to
find anything.

I have a method that accepts Action<Foo>. I'd like to use Moq like
this:

var action = _mockFactory.Create<Action<Foo>>();

action.Setup(a => a(myFoo));

target.CallMethod(action.Object);

Currently this causes a System.ArgumentException: Type to mock must be
an interface or an abstract or non-sealed class.

What is the recommended pattern for testing this? Ideally I wouldn't
define a new interface with a single member having signature
Action<Foo>. From what I know about reflection emit and expression
trees, there's no technical limitation that prohibits this scenario.
Maybe you have a design preference for this?

I'm using version 3.1.416.3.

Drew Noakes.

Drew Noakes

unread,
May 13, 2009, 10:20:26 AM5/13/09
to Moq Discussions
This could also be used to easily check for event invocations:

var action = _mockFactory.Create<Action<Foo>>();

action.Setup(a => a(myFoo));

target.SomeEvent += action.Object;

target.RaiseEvent();

Again, maybe there's a pattern for this I am not aware of. I didn't
see it on the Wiki however.

Daniel Cazzulino

unread,
May 13, 2009, 11:09:36 AM5/13/09
to moq...@googlegroups.com, D.No...@mwam.com
Why don't you just pass-in an empty delegate?


   target.CallMethod(foo => { });

?

And if you need to test for its invocation, it would be equally easy:

Foo fooArg = null;

target.CallMethod(f => fooArg = f);
Assert.IsNotNull(fooArg);


/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471

Drew Noakes

unread,
May 13, 2009, 11:55:16 AM5/13/09
to Moq Discussions
> Why don't you just pass-in an empty delegate?
>
>    target.CallMethod(foo => { });
>
> And if you need to test for its invocation, it would be equally easy:
>
> Foo fooArg = null;
>
> target.CallMethod(f => fooArg = f);
> Assert.IsNotNull(fooArg);

This is similar to what I ended up doing, but it's not very robust.
For example, if I want to assert that the action was called N times, I
have to introduce a count property as well, and if there are several
actions such as this, it's harder to track.

Foo fooArg = null;
int callCount = 0;
target.CallMethod(f => { fooArg = f; callCount++; });
Assert.AreEqual(fooArg, expectedFooArg);
Assert.AreEqual(1, callCount);

...is definitely nastier than...

var action = _mockFactory.Create<Action<Foo>>();

action.Setup(a => a(expectedFooArg)).AtMostOnce();

target.CallMethod(action.Object);

The same is true of my follow-up post for events.

The code example gets worse if you have two such actions to track (not
to mention more than one argument in the delegate):

Foo fooArg1 = null;
Foo fooArg2 = null;
int callCount1 = 0;
int callCount2 = 0;
target.CallMethod(f => { fooArg1 = f; callCount1++; });
target.CallMethod(f => { fooArg2 = f; callCount2++; });
Assert.AreEqual(fooArg1, expectedFooArg1);
Assert.AreEqual(fooArg2, expectedFooArg2);
Assert.AreEqual(1, callCount1);
Assert.AreEqual(1, callCount2);

...versus...

var action1 = _mockFactory.Create<Action<Foo>>();
var action2 = _mockFactory.Create<Action<Foo>>();

action1.Setup(a => a(expectedFooArg1)).AtMostOnce();
action2.Setup(a => a(expectedFooArg2)).AtMostOnce();

target.CallMethod(action1.Object);
target.CallMethod(action2.Object);

Daniel Cazzulino

unread,
May 13, 2009, 1:13:27 PM5/13/09
to moq...@googlegroups.com
Don't think we'll support this anytime soon (unless we get a patch, as usual :)).




/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


Daniel Cazzulino

unread,
Mar 2, 2010, 7:53:48 PM3/2/10
to Royston Shufflebotham, moqdisc
now it makes sense :)

would you mind filing an Issue with some tests you'd like to compile and pass?


/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Tue, Mar 2, 2010 at 19:32, Royston Shufflebotham <roy...@shufflebotham.org> wrote:
Here's a test I've already got (which compiles happily but doesn't yet pass as I don't have it all working) to test verifiable Setups on mocked delegates:

        [Fact]
        public void RoystonTest()
        {
            var mockRaiser = new Mock<INotifyPropertyChanged>();
            var mockListener = new Mock<PropertyChangedEventHandler>(MockBehavior.Strict);

            mockRaiser.Object.PropertyChanged += mockListener.Object;

            mockListener
                .Setup(x => x(mockRaiser.Object, It.Is<PropertyChangedEventArgs>(pcea => pcea.PropertyName == "blob")))
                .Verifiable();
            mockRaiser.Raise(x => x.PropertyChanged += null, new PropertyChangedEventArgs("blob"));
            mockListener.Verify();
        }

i.e. instead of your lambda looking like
mock.Setup(x => x.SomeCall(parameter1, ...))
you get
mock.Setup(x => x(parameter1, ...))

(and then internally that call on the delegate makes the real call to the mocked/proxied interface.)

Make sense?

My team and I basically do this manually quite a lot: if we have a FooListener delegate for an event somewhere, we end up cranking out an IFooListener interface with a method on it that matches the delegate signature, create a Mock<IFooListener> using Moq, subscribe that mock to the event, and then we can make assertions about what happened to that interface when the class under test is manipulated. (To find out whether the event was raised, and make assertions about its EventArgs, basically.)  Works well, but it's messy having to write the interface by hand every time.  I'm resisting calls to move (back) to Rhino Mocks - which does support exactly this sort of delegate mocking - as I much prefer the natural AAA syntax of Moq.

Cheers,
 Royston.


On 02/03/2010 22:18, Daniel Cazzulino wrote:
Not sure about this.
How are you going to Setup/Verify if the thing is a Func? (say). How will the lambda look like?


/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Tue, Mar 2, 2010 at 17:45, Royston Shufflebotham <roy...@shufflebotham.org> wrote:
Hi there,

I've finally gotten some time to have a look into this (arranging for Moq to support mocking of delegates).  It seems that a simple way to achieve it is to:
  • create an interface dynamically with a method declared on it whose signature matches that of the requested delegate
  • create a proxy instance for the interface (with all the usual Moq recording support)
  • create a real delegate of type D pointing at the method on the mocked interface instance
  • return that
At that point, calls against the 'mocked' delegate get turned into calls against the mocked interface, and in theory all of the normal recording/setup/verify stuff should work.  (I've essentially been doing this for months by hand with Moq, and it's getting boring!)

I've managed to get some way into this, and have Moq creating the dynamic interface, proxying it and returning the delegate instances; the problem area is that the object that calls are recorded against (the interface) are not the same object that was returned (the delegate) which looks like it goes against some Moq code assumptions and means a little more refactoring than I'd hoped.

Would you be happy to receive barely-compiling patches (against Moq Subversion) trunk and help out where I don't quite understand some of the implications?

Cheers,
 Royston.



On 14/07/2009 23:31, Daniel Cazzulino wrote:
Looking forward to it!
All help is appreciated :)


/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Tue, Jul 14, 2009 at 2:51 PM, Royston <roy...@shufflebotham.org> wrote:
That's a shame.  It's a useful piece of functionality I was used to
having in Rhino Mocks...

<http://ayende.com/Wiki/Default.aspx?Page=Rhino+Mocks+Mocking
+Delegates>

Just to clarify why it's actually useful:

In the same way that we want to be able to check (using Moq) that a
class-under-test calls a particular method, it's very useful to be
able to test that your class raises an event (i.e. calls some
EventHandler or calls some other delegate).  For instance, I currently
have an implementation of INotifyPropertyChanged and want to check
that events are raised correctly when setters are called.  (I'm
interested in testing it as it's not completely trivial as some of the
properties are - unfortunately - interdependent.)   But it would be
good to make the sort of assertions about the delegate calls that we
can about other methods, e.g. how many times, with what parameters,
etc.

If it's a reasonably simple thing to do for Moq, I'd be happy to knock
it together; I've certainly contributed to the Rhino Mocks source in
the past and that was pretty easy...

Cheers,
 Royston.

Daniel Cazzulino

unread,
Jun 3, 2010, 10:07:14 AM6/3/10
to Royston Shufflebotham, moqdisc
it will be there by v4 RTM.


/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Wed, Jun 2, 2010 at 18:30, Royston Shufflebotham <roy...@shufflebotham.org> wrote:
Hi there,

It's been almost three months since I submitted this fix, which does include full unit tests.  Any chance we can get it into the main source soon, preferably before the v4 release? (It's not in the v4 beta 3 code.)


Cheers,
 Royston.

On 05/03/2010 23:11, Daniel Cazzulino wrote:
Thanks a bunch!

Your contribution will almost surely end up in v4 :)


/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Fri, Mar 5, 2010 at 18:12, Royston Shufflebotham <roy...@shufflebotham.org> wrote:
All done.  Bizarrely the thing that took significant time was as I was preparing the patch and realised you were using tabs in the source, not spaces, and had to reformat my changes. That took more time to fix than did the dynamic interface fixups and reuse of a ModuleScope!

I've attached the patch to the issue raised, at http://code.google.com/p/moq/issues/detail?id=235.

I've focused on keeping the changes minimal, so whilst I introduced a CallInfo class to wrap up the bits of data in common between an InvocationExpression and a MethodCallExpression, I assigned that to a variable called methodCall so that the rest of the code didn't change.

As I mentioned in the issue, the public Moq API is totally unchanged. It just now allows delegate mocking whereas it didn't before.

Let me know what you think - I'd love to see this make it into a release in the near future?

Regards,
 Royston.

P.S. In case I haven't already said - thanks for Moq, and for making the A-A-A pattern so easy to specify. I used to use Rhino Mocks (a lot) but find it a lot easier to get others up to speed on the Moq AAA syntax.



On 04/03/2010 00:06, Daniel Cazzulino wrote:
Awesome progress!

keep me posted :)


/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Wed, Mar 3, 2010 at 19:42, Royston Shufflebotham <roy...@shufflebotham.org> wrote:
Fine. I raised it as issue 235.

Regarding implementation, I've actually got it essentially all working now: all of the tests I put up on that issue now pass with the changes I've made, and, as far as I can see, the only problem I have right now is that the tests don't pass when all run together in one go because there's a problem with the automatic generation of the dynamic interface: I just need to investigate the way DynamicProxy spits out types a little more, and maybe ModuleScopes.  Should be fairly quick...

I've managed to keep the changes fairly localised (Extensions.cs, Mock.cs, Mock.Generic.cs, tiny changes to de-genericise IProxyFactory/CastleProxyFactory) and I've kept the changes minimal.  The main change is that instead of assuming we have a MethodCallExpression in Setup/Verify, it might be an InvocationExpression, and so we retrieve the method, arguments and target object in a slightly different way.

I'll do some tidyups, get the above problem sorted out (hopefully) and chuck some diffs at you soon with any luck.

Cheers,
 Royston.


On 03/03/2010 14:57, Daniel Cazzulino wrote:
nah, I could use help :)

so feel free to send the impl too, he


/kzu

--
Daniel Cazzulino | Developer Lead | XML MVP | Clarius Consulting | +1 425.329.3471


On Wed, Mar 3, 2010 at 10:19, Royston Shufflebotham <roy...@shufflebotham.org> wrote:
Sure. I'll get them together.  They should compile with existing Moq (there's no external API change needed) but they explode when run.

I've also got a partial implementation together. Shall I carry on with that, or are you going to zip off and do the implementation in half the time? :)

Cheers,
 Royston.
Reply all
Reply to author
Forward
0 new messages