Moq pros and cons

464 views
Skip to first unread message

andreister

unread,
Jan 5, 2009, 10:15:20 AM1/5/09
to Moq Discussions
Hi, please have a look at my take on pros and cons for Moq.

Do you agree/disagree? Anything else you might consider as a pro/con?

Pros:
1. Open source and free.
2. Type safe.
3. Simple API.
4. Can mock classes.
5. Allows both strict and non-strict mocks.

Cons:
1. Poor internal error messages.
2. Need to use "mock.Object" property if we pass the mocked interface/
class over.
3. Cannot mock non-virtual, non-abstract and static methods, cannot
mock sealed classes and private interfaces.

Daniel Cazzulino

unread,
Jan 5, 2009, 11:21:12 AM1/5/09
to moq...@googlegroups.com
could you elaborate on "Poor internal error messages."?

which ones could be improved? concrete repros would be appreciated deeply!

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

Brad Stiles

unread,
Jan 5, 2009, 11:26:16 AM1/5/09
to moq...@googlegroups.com
> 2. Need to use "mock.Object" property if we pass the mocked interface/
> class over.

I, for one, do not consider this a detriment. It makes it clear just
by looking at the code that the mocked object, rather than the mock
itself, is what's being referenced.

Brad

gerry_lowry (alliston ontario canada)

unread,
Jan 5, 2009, 11:39:37 AM1/5/09
to moq...@googlegroups.com
http://stephenwalther.com/blog/archive/2008/06/12/tdd-introduction-to-moq.aspx
"TDD : Introduction to MoQ"

Stephen Walther makes some interesting comments in the above article.

Stephen Waltrefers to Martin Fowler's http://martinfowler.com/articles/mocksArentStubs.html
"Mocks Aren't Stubs" article (Last significant update: 2007-01-02).

According to (my novice interpretation of) Martin Fowler's article, it seems that behaviour verification
is highly desirable but Stephen writes that MoQ can perform behaviour verification only in a limited way.
Martin Fowler writes that in some "edge" cases, behaviour verification is "the wise choice".

QUESTION: Stephen's article was posted last June 12th ~~ since MoQ has presumably
evolved since then, is Stephen's comment that the MoQ framework can be
used to perform "limited" behaviour verification still as valid now as it was
when Stephen posted his "TDD : Introduction to MoQ" article last June?


Regards,
Gerry (Lowry)

andreister

unread,
Jan 5, 2009, 12:03:37 PM1/5/09
to Moq Discussions
It depends on how much behavior do you want to test/mock.

I have to admit (Daniel will correct me if I'm wrong) that Moq is
dedicated to state based testing, and interaction testing is more a
side feature probably even implemented with a bit of reluctance :)

So - yes, you can mock/test interactions. Consider this simple case:

[Test]
public void TouchHotIron_Yell()
{
var hand = new Mock<IHand>();
var mouth = new Mock<IMouth>();

hand.Expect(x => x.TouchIron(It.IsAny<Iron>())).Throws(new
BurnException());
mouth.Expect(x => x.Yell()).Verifiable();

var brain = new Brain(hand.Object, mouth.Object);
brain.TouchIron(new Iron { IsHot = true });

mouth.Verify();
}


mouth.Verify verifies whether the Yell method was actually called.



On Jan 5, 5:39 pm, "gerry_lowry \(alliston ontario canada\)"
<gerry.lo...@abilitybusinesscomputerservices.com> wrote:
> http://stephenwalther.com/blog/archive/2008/06/12/tdd-introduction-to...
>                          "TDD : Introduction to MoQ"
>
> Stephen Walther makes some interesting comments in the above article.
>
> Stephen Waltrefers to Martin Fowler'shttp://martinfowler.com/articles/mocksArentStubs.html

andreister

unread,
Jan 5, 2009, 12:09:02 PM1/5/09
to Moq Discussions
Imagine we call Verify on some method to make sure it was called only
once.
If the method was called twice, we'd see

------------------------------------------
Expected only 1 calls to IMouth.Yell()
------------------------------------------

That neither provides any info about the variable name, nor does it
tell how many times the method was actually called.

Compare to NMock2 output:

------------------------------------------
NMock2.Internal.ExpectationException: not all expected invocations
were performed
Expected:
1 time: mouth.Yell(any arguments) [called 10 times]
------------------------------------------

I added it as an issue at http://code.google.com/p/moq/issues/detail?id=115

andreister

unread,
Jan 5, 2009, 12:13:25 PM1/5/09
to Moq Discussions
Brad - yeah I understand, and I have no doubt it's done on purpose -
but it just doesn't feel ok to me :)

Tests should be natural, and the less you notice the mocking
framework, the more powerful is the framework.

I also don't like when mocked objects have their variable names
prepended with "mock":
"var mockProduct = ..."
instead of a mere
"var product = ..."

Daniel Cazzulino

unread,
Jan 5, 2009, 12:14:15 PM1/5/09
to moq...@googlegroups.com
I've added a comment on that post.
Indeed, Moq can do every behavior verification test you want to perform, with the only exception being invocations ordering, which is IMO an over-specification anyway.

Daniel Cazzulino

unread,
Jan 5, 2009, 12:20:53 PM1/5/09
to moq...@googlegroups.com
I'd be happy if people moved away from Verify() and VerifyAll() and instead used the more AAA (act-arrange-assert) pattern with explicit verifications:

[Test]
public void TouchHotIron_Yell()
{
   var hand = new Mock<IHand>();
   var mouth = new Mock<IMouth>();

   hand.Expect(x => x.TouchIron(It.IsAny<Iron>())).Throws(new
BurnException());

   var brain = new Brain(hand.Object, mouth.Object);
   brain.TouchIron(new Iron { IsHot = true });

   mouth.Verify(x => x.Yell());
}


this makes it more explicit the error when the verification is not satisfied (simply click the line that failed :)), and allows you to put all your verification statements at the bottom together with your Asserts.

Daniel Cazzulino

unread,
Jan 5, 2009, 12:58:41 PM1/5/09
to moq...@googlegroups.com
It was not done on purpose, it was the result of a limitation in the .NET framework (see https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=318122). If I could implement implicit conversion from Mock<T> to T we could do away with this :)

we also didn't want to mess with your intellisense experience by adding Moq methods as extension methods on System.Object, which would allow you to use the instance directly while calling mocking methods on it. (I believe this is what Rhino does and a very concrete complain people reported (see http://weblogs.asp.net/rosherove/archive/2008/12/03/isolation-frameworks-lessons-from-the-wild.aspx#6775688). 

it is also incorrect that you'd get such a meaningless error message with Moq. What you get is a direct exception at the callsite when the method is called (say) the second time when it was expected only once. You don't need to verify that, just as you don't need to verify that a method was not called. If you set an expectation for no calls, and it's called, it throws right-away. This makes it MUCH easier to diagnose your own code to see who's calling it and at which time and with which state. Same for N calls...

do you have another example where the error message could be clearer?

andreister

unread,
Jan 6, 2009, 4:54:01 AM1/6/09
to Moq Discussions
Hmm, I didn't think of putting "mouth.Verify(x => x.Yell());" at the
bottom - thanks!

Putting interaction verifications along with asserts looks more
natural.

andreister

unread,
Jan 6, 2009, 5:40:20 AM1/6/09
to Moq Discussions
Thanks for the link to the microsoft feedback page - really
interesting!

However, I'm probably missing something in your explanation. Look at a
piece of Rhino Mocks code for creating a mock:
----------------------------------------------------------------------
public static T GenerateMock<T>(params object[]
argumentsForConstructor)
where T : class
{
...
T mock = repository.DynamicMock<T>(argumentsForConstructor);
...
return mock;
}

(more details at https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-mocks/Rhino.Mocks/MockRepository.cs
for anyone curious)
----------------------------------------------------------------------
It returns T, not some mock object that has a property of type T. It's
*not* an extension or something.



Then, again, the same is true for NMock2
----------------------------------------------------------------------
public InterfaceOfMock NewMock<InterfaceOfMock>()
{
return (InterfaceOfMock)this.NewMock(typeof(InterfaceOfMock));
}

(just look at http://nmock2.svn.sourceforge.net/viewvc/nmock2/trunk/src/NMock2/Mockery.cs?view=markup
for more details)
----------------------------------------------------------------------


And for some reason Moq turned on a different path, by allowing to
create mock objects directly with "new":
var mock = new Mock<IDontUnderstandWhy>();


That's what I'm curious about. Some people explain to themselves that
passing "foo.Object" rather than "foo" is much better and readable and
so on... not sure I've heard a better explantion.

... and as a side note, about extension methods on System.Object and
obusing intellisense - I was amazed by Moq's IHideObjectMembers ;)


On Jan 5, 6:58 pm, "Daniel Cazzulino" <kzu....@gmail.com> wrote:
> It was not done on purpose, it was the result of a limitation in the .NET
> framework (seehttps://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx...).
> If I could implement implicit conversion from Mock<T> to T we could do away
> with this :)
> we also didn't want to mess with your intellisense experience by adding Moq
> methods as extension methods on System.Object, which would allow you to use
> the instance directly while calling mocking methods on it. (I believe this
> is what Rhino does and a very concrete complain people reported (seehttp://weblogs.asp.net/rosherove/archive/2008/12/03/isolation-framewo...
> ).

andreister

unread,
Jan 6, 2009, 5:51:47 AM1/6/09
to Moq Discussions
>What you get is a direct exception at the callsite

In my experience, you read error messages much more often than you
debug tests.

And if a clear error message really nails it down to the problem,
provides as many details as possible, and allows you to avoid
debugging - that's good.

It obviously means much more work inside the framework, with a
(seemingly) little change in error messages, but it saves time while
fixing the broken tests.

(On a second thought, error messages *in tests* are WAY MORE IMPORTANT
than internal errors from the framework, and to be honest people
rarely write proper error messages themselves... so perhaps all the
aforesaid is true only for those who pay attention to error messages
they write *themselves*. What do you think?)

>do you have another example where the error message could be clearer?
will try to create something


On Jan 5, 6:58 pm, "Daniel Cazzulino" <kzu....@gmail.com> wrote:
> It was not done on purpose, it was the result of a limitation in the .NET
> framework (seehttps://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx...).
> If I could implement implicit conversion from Mock<T> to T we could do away
> with this :)
> we also didn't want to mess with your intellisense experience by adding Moq
> methods as extension methods on System.Object, which would allow you to use
> the instance directly while calling mocking methods on it. (I believe this
> is what Rhino does and a very concrete complain people reported (seehttp://weblogs.asp.net/rosherove/archive/2008/12/03/isolation-framewo...
> ).

Daniel Cazzulino

unread,
Jan 7, 2009, 3:33:13 PM1/7/09
to moq...@googlegroups.com
On Tue, Jan 6, 2009 at 8:51 AM, andreister <andre...@gmail.com> wrote:

>What you get is a direct exception at the callsite

In my experience, you read error messages much more often than you
debug tests.

I think I didn't make myself clear enough.
You don't need to DEBUG the tests in order to see where the exception happened, exactly called by whom. Then, if you want (or can't figure out why someone is calling a given method) then you can simply click on the exception in the output window (or test result window), go to the offending caller location, and set a breakpoint there. 

The callstack of the exception itself is evident enough of where the wrong call is being made. This is better IMO than having an error raised later in the test, when you've loosed all the context.

Daniel Cazzulino

unread,
Jan 7, 2009, 3:38:06 PM1/7/09
to moq...@googlegroups.com
Precisely. Rhino makes the choice of returning the actual <T> rather than a mock of that T, but then in order to call Expect, Stub, etc. on it, it does so by introducing extension methods on *any* T (which is a class/interface). See https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-mocks/Rhino.Mocks/RhinoMocksExtensions.cs

this means that with Rhino, *every* object you have instantiated in your test has all those extension methods, when they do not apply actually to the object:

var obj = new object();
obj.Expect(o => o.ToString()); 

:S:S

We made the explicit choice of not going this path, as it pollutes your intellisense experience for every object that is not a mock.

andreister

unread,
Jan 11, 2009, 10:54:11 AM1/11/09
to Moq Discussions
Great, thanks for the explanation.

In the meantime, I'm writing a series of mocking frameworks reviews
that (hopefully) would eventually form a chapter in a book. Would you
mind flicking though http://codevanced.net/post/Touching-a-hot-iron-Moq.aspx
and let me know (either here or there) if there are any features I
missed that absolutely needed to be covered, or anything I used
incorrectly, etc.

Thanks a lot in advance! (I wrote a private message but it probably
was eaten by your spam filter :))

On Jan 7, 9:38 pm, "Daniel Cazzulino" <kzu....@gmail.com> wrote:
> Precisely. Rhino makes the choice of returning the actual <T> rather than a
> mock of that T, but then in order to call Expect, Stub, etc. on it, it does
> so by introducing extension methods on *any* T (which is a class/interface).
> Seehttps://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhi...
> this means that with Rhino, *every* object you have instantiated in your
> test has all those extension methods, when they do not apply actually to the
> object:
>
> var obj = new object();
> obj.Expect(o => o.ToString());
>
> :S:S
>
> We made the explicit choice of not going this path, as it pollutes your
> intellisense experience for every object that is not a mock.
>
>
>
> On Tue, Jan 6, 2009 at 8:40 AM, andreister <andreis...@gmail.com> wrote:
>
> > Thanks for the link to the microsoft feedback page - really
> > interesting!
>
> > However, I'm probably missing something in your explanation. Look at a
> > piece of Rhino Mocks code for creating a mock:
> > ----------------------------------------------------------------------
> > public static T GenerateMock<T>(params object[]
> > argumentsForConstructor)
> >  where T : class
> > {
> >   ...
> >   T mock = repository.DynamicMock<T>(argumentsForConstructor);
> >   ...
> >   return mock;
> > }
>
> > (more details at
> >https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhi...
> > for anyone curious)
> > ----------------------------------------------------------------------
> > It returns T, not some mock object that has a property of type T. It's
> > *not* an extension or something.
>
> > Then, again, the same is true for NMock2
> > ----------------------------------------------------------------------
> > public InterfaceOfMock NewMock<InterfaceOfMock>()
> > {
> >  return (InterfaceOfMock)this.NewMock(typeof(InterfaceOfMock));
> > }
>
> > (just look at
> >http://nmock2.svn.sourceforge.net/viewvc/nmock2/trunk/src/NMock2/Mock...

Daniel Cazzulino

unread,
Jan 12, 2009, 6:10:29 AM1/12/09
to moq...@googlegroups.com
Here's one thing that is missleading:

"if we expected mouth.Yell() to be called once but it was called twice, we'd just see "Expected only 1 calls to IMouth.Yell()" that does not even provide how many times the method was actually called. "

What you'd see is an exception raised at the exact call site that is performing the second invocation. You don't need to wait until 5 wrongly-made invocations to realize it! And clicking on the output window/exception will take you straight to the offending calling code. This is much better than recording how many times it was wrongly called. The stacktrace is your friend here, and you can debug the exact place the exception is being thrown to see exactly what state are your objects have when it happened.

It's not uncommon for people used to other mocking frameworks to expect the error messages to tell them what went wrong, rather than using .NET built-in mechanism (much more debugger-friendly too!) of simply throwing an exception at the precise time when the unexpected happens.

I'd list it as a plus, most certainly.

So I'm still not clear on other examples that make up for the "1. Poor internal error messages.". I'm interested in cases where we can improve.

Thanks!
Reply all
Reply to author
Forward
0 new messages