Touching a hot iron: Moq

January 4, 2009 19:31

In June 1917, one Russian deputy said that there was no political party willing to demand that the Provisional Government resign and hand power over to it. It was said on a public meeting, and suddenly Vladimir Lenin stood up and called out: "There is such a party!"

In January 2007, Ayende Rahien said that all mocking frameworks, either explicitly or implicitly, use Record/Replay model on mocked objects. It was
stated in Rhino Mocks documentation, and suddenly (er, 11 months later) Daniel Cazzulino stood up and said on his blog: "Well, it's not true anymore".

That's the story.

The reason behind Moq was to decrease learning curve by avoiding Record/Replay idiom and hiding the differences between mocks/stubs/fakes/etc. Season with strong typing via lambda expressions, and you'll get this framework. Our touch-and-yell test[1] would look like


[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());
}


Easy but sesquipedalian: how come?

Moq allows you to forget about differences between mocks and stubs. If you want to ensure a method gets called you just add .Verifiable() at the end of the mocked method, as we see in the sample above. (Alternatively, you can call VerifyAll() instead of Verify() in the end, but I wouldn't recommend that and it's much better to stick to one approach.)

This approach makes Moq an easy grasp. 

I'm not sure if knowing less is a way to become a good developer, but if it helps newbies to catch up, it's fine. Just don't forget to learn about those mocks vs. stubs vs. fakes later on, when you become more comfortable with mocking!

A scary thing is that Moq does use the term "stub", but only for properties (look for
StubExtensions in the source code, if you're curious). I hope it wouldn't mean Moq would eventually digress from the common vocabulary, eh?

And, yeah, please notice this sesquipedalian syntax: mocked objects do not implement the interfaces they mock. Instead, we should use mock.Object property if we need the one (look at how Brain type is created in the example above).

 

Pros and cons.

Both strict and non-strict mocks are supported (it is controlled by the MockBehavior enum, with non-strict mocks created by default).

The framework can mock both interfaces and classes, and
lambda expressions make those mocks type safe and refactoring friendly. However, like Rhino Mocks, Moq uses Castle Dynamic Proxy for mocking hence the same pitfalls: you cannot mock non-virtual, non-abstract methods, and cannot mock sealed classes and private interfaces. And, again, of course, you cannot mock static methods.

Learning Moq is really slick (should I say sliq?) because of straightforward API and available source code (which helps to understand some parts that might not be that straightforward to you).

Error messages could have been better: if
mouth.Yell() hasn't been called, we'll see

Moq.MockVerificationException: The following expectations were not met:
IMouth x => x.Yell()
   

This is not really different from what we've seen in Rhino Mocks. And sometimes it's maybe even worse: 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.


Sum up.

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.
 



Footnotes:


[1] If you happen to come across this post before reading the original story of touching a hot iron, you may want to read it over. And here is the code for the types used in the example.
 


Comments are closed