The Downside Of Providing An API Through Extension Methods

9 commentsWritten on August 26th, 2010 by
Categories: Code Quality, testing

I recently used the excellent Moq mocking library for the first time, and i noticed a difference between Moq and Rhino Mocks (what i usually use) that i found interesting.

Consider the following useless and contrived example code:

    public interface ISomeComponent
    {
        void DoSomething();
    }
 
    public class SomeClass
    {
        private ISomeComponent someComponent;
 
        public SomeClass(ISomeComponent someComponent)
        {
            this.someComponent = someComponent;
        }
 
        public void DoSomethingReallyImportant()
        {
            someComponent.DoSomething();
        }
    } 

Now suppose that we want to verify in a test that the DoSomethingReallyImportant method of SomeClass actually calls the DoSomething method of its ISomeComponent dependency.

With Moq, we could do that like this:

    [TestFixture]
    public class TestWithMoq
    {

        [Test]
        public void CallsDoSomethingOnSomeComponent()
        {
            var mock = new Mock<ISomeComponent>();
            var someObject = new SomeClass(mock.Object);
 
            someObject.DoSomethingReallyImportant();
 
            mock.Verify(m => m.DoSomething());
        }
    }

And with Rhino Mocks, it would look like this:

    [TestFixture]
    public class TestWithMoq
    {
        [Test]
        public void CallsDoSomethingOnSomeComponent()
        {
            var mock = new Mock<ISomeComponent>();
            var someObject = new SomeClass(mock.Object);
 
            someObject.DoSomethingReallyImportant();
 
            mock.Verify(m => m.DoSomething());
        }
    }

Not much of a difference, right? Except that Rhino Mocks provides you with a proxy that implements the ISomeComponent interface and Moq provides you with a generic Mock object, which contains a proxy that implements the ISomeComponent interface and is exposed through the Object property. Other than that, the tests are very similar.

The key difference is what you experience when you write the tests, as the 2 pictures below will illustrate:

Since Moq's API is not fully based on Extension Methods, you get a normal and clean IntelliSense experience. Rhino Mocks on the other hand provides its API (at least the non-legacy stuff) solely through extension methods, which leads to all of them being included in your IntelliSense, even when they don't make any sense at all.It's obviously not a major issue, but i was suprised with how much i liked not seeing all of the extension methods all the time while writing tests.

  • Vagif Abilov

    Another issue with extension methods is that they are language-specific. You will see them in C#, but not F#, for example.

  • http://benpittoors.wordpress.com den Ben

    +1 for Moq

  • Alex Simkin

    Cool guys are using NSubstitute now.

  • http://benpittoors.wordpress.com den Ben

    NSubstitute looks nice, but it also uses extension methods.

  • http://fromthedevtrenches.blogspot.com/ Carel Lotz

    We went through the exercise of migrating onto Moq about 2 months ago since we are >= .NET 3.5 in our system. I must say I have not regretted it one day. API is nice and clean compared to the the Rhino.Mocks API. Granted Rhino.Mocks has been around a lot longer so it carries a lot more legacy but overall I find it easier to program and with also easier to mentor other developers that are new to mocking using Moq.

  • Alex Simkin

    For a very detailed (but somewhat biased) comparison of frameworks look this 12-part series.

    http://www.richard-banks.org/2010/07/mocking-comparison-part-1-basics.html

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #674

  • http://devlicio.us/blogs/tim_barcz/ Tim Barcz

    It’s simply a tradeoff, in order to get less intellisense “noise” you have to take on more noise with .object in your code whenever you want to access the mock object (in Moq).

    • http://davybrion.com Davy Brion

      True, but i typically access the mock far less than anything else, so for me it’s less noise :)