Partial Mocks explained

April 8th, 2008

If you are wondering what is prompting this post, it is the fact that on my last post I got schooled by Jeff Brown of Bits-in-Motion.   Jeff is also one of the minds behind Gallio and MBUnit.  You can only hope to be told you are completely wrong by such a guy. He was very nice about it actually, just stating a preference for a different way of handling the same problem.  My problem was that his solution was better than mine.  Much better.

Where it led me was to re-investigate Partial Mocks in Rhino Mocks.  My original misunderstanding of Partial Mocks was that they would only mock Abstract Classes.  A partial mock will mock ANY class — but only the Partial mock will only mock abstract methods.  That small misunderstanding has caused me to loose untold amount of hair and good will towards all men.

So I’m going to re-implement my class methods.  Here you go:

public class MyClass
{
    public int Foo()
    {
        // stuff happens here
        int i = Bar();
        // do more stuff here    
        return i + 5;
    }
    public virtual int Bar()
    {
       // do some logic
       return 1;
    }
}

A few changes here.  First, I removed the delegate and renamed BarInternal back to Bar.  Second, I marked the Bar method as virtual

They key point about a virtual method is that you can provide an implementation, and then a inherited class can completely override that method.  That is what the Partial Mock is allowing us to do.

So how do I write my tests?  If you don’t like using Rhino Mocks you do this:

[Test]
public void FooTest()
{
    int expected = 7;
    int result = 0;
    MockRepository mock = new MockRepository();
    MyClass c = mock.PartialMock<MyClass>();

    using (mock.Record())
    {
        Expect.Call(c.Bar()).Return(2);
    }
    using (mock.Playback())
    {
        result = c.Foo();
    }

    Assert.AreEqual(expected, result);
}

Obviously, now my test is referencing the Rhino Mocks library.  The variable mock is the Mock Repository.  Now the big change is that I don’t create MyClass directly, but through the Rhino Mocks PartialMock method.

Next, I tell the mock repository to expect a call to c.Bar, and when called return 2.  That is what is happening in the using (mock.Record()) section of the code.  Then, in the mock.Playback section, I call Foo().

One other quick note, if we were to rewrite Foo such that it no longer called Bar this test will fail.  The Expect.Call part tell the mock repository that the method Bar will be called, and if it isn’t there is a problem.  There are ways around that as well, but that is a topic for another day.

Where does that leave us now?  Aside from the odd “virtual” keyword thrown into our production code, this is the code as you would have originally written it, even without TDD.  I don’t like making API changes just to satisfy testing, but I am very OK with this change.

 

But what about that new kid on the block?  You know, Moq.

I still love Rhino Mocks, but I can’t help but want to play with a new toy.  So here is the same thing, but in Moq:

[Test]
public void Foo_moq_test()
{
    Mock<MyClass> mock = new Mock<MyClass>();
    mock.Expect(x => x.Bar()).Returns(2);

    MyClass c = mock.Object;
    int result = c.Foo();
    Assert.AreEqual(7, result);
}

So as you should be able to see, Moq is a very different animal than RhinoMocks.  There is no Record or Playback (the web site calls those confusing, I disagree, but still), and the Expect happens with a anonymous delegate (in the form of the Lambda Expression “x => x.Bar()” where x is of type MyClass).

The cool part is that you can get the same results with less code using Moq.  That has been the main advantage all along.  My informal testing also reveals that Moq is just a hair faster than Rhino Mocks (but not fast enough to warrant switching frameworks).

  • http://blog.bigs-in-motion.com/ Jeff Brown

    Looks good!

    Anyways, don’t worry too much about being “schooled.” I was actually the one who asked Ayende to add PartialMock in the first place and I contributed a few other things besides. So Rhino.Mocks is pretty dear to my heart. :-)

    Now Moq is starting to look pretty good with those tidy little lambdas… There’s a lot of potential for more expressive syntax with C# 3.0. mmm!

  • http://blog.bits-in-motion.com/ Jeff Brown

    Argh, I got the wrong website link in there again. FireFox “helpfully” cached it for me from earlier. *sigh*

  • Pingback: Links Today (2008-04-10)

  • J-F Pinero

    Thanks for the quick comparison. We use Rhino at work (well my small team does) and I’ve been trying to convince them to switch over to Moq since we started using c# 3.0.

    This will be a nice little “Hello Moq World” example for them.

  • http://symyx.com Palle Cogburn

    Thank you. This was very helpful to me. I am learning Moq and I was having a problem testing classes that had statements like this:
    Context.Current.ActiveProcessor.GetInstrument(InstrumentId id)

    I now realize that the design needs to be changed to be testable to isolate the statement into a separate method.

    Bottom line is: “If you can’t test it, your design is wrong.”

  • http://linqtojohn.wordpress.com John

    Thanks, good explanation.