Sep 11 2010

The Right Way to Do Automocking with Ninject

Category: Moq | TestingMatt @ 13:07

While StructureMap is definitely my IoC container of choice, it’s not the only game in town.  At my new job, our existing project uses Ninject.   One of my first tasks at this new job was integrating my SpecsFor “framework” into the existing projects.  The original version of SpecsFor worked with StructureMap and leveraged its auto-mocking container.  While Ninject has an auto-mocking extension, ninject.moq, it is sorely lacking when compared to StructureMap’s offering.  In this post, I’ll show you how to modify it into a useful automocking container, and I’ll also show you how easily SpecsFor can be adapted to Ninject using this working container.

Fixing Ninject.Moq

Ninject’s auto-mocking extension project can be found on github.  Yes, you have to build it from source if you want to use it.  However, don’t bother: the existing approach to auto-mocking is flawed and doesn’t work.  Here’s a very simple test case to illustrate the problem:

[Test]
public void Kernel_returns_same_mock_instance_for_all_requests_for_that_type()
{
    var kernel = new MockingKernel();

    //This assert fails.
    Assert.AreSame(kernel.Get<IDummyService>(), kernel.Get<IDummyService>());
}

That’s right, the container returns a new mock every time, which makes it difficult to setup expectations to be injected into a class.  It also can’t create the class-under-test directly without jumping through some additional hoops.  You have to bind the class to itself, like so:

[Test]
public void Kernel_can_create_class_under_test()
{
    var kernel = new MockingKernel();
    //Why should I have to do this??
    kernel.Bind<DummyClass>().ToSelf();

    Assert.IsNotNull(kernel.Get<DummyClass>());
}

Fortunately, these problems are easy to fix, and in fact Derick Bailey has already fixed them in his port of ninject.moq to Rhino Mocks.  You can check out his code on github.

First, we need to eliminate the self-binding requirement for the class under test.  We can do that by adding a little extra logic to the MockingKernel’s HandleMissingBindingMethod:

protected override bool HandleMissingBinding(Type service)
{
    bool selfBindable = TypeIsSelfBindable(service);

    if (selfBindable)
    {
        Bind(service).ToSelf().InSingletonScope();
    }
    ...
}

If a type is self-bindable, we’re binding it to itself with singleton scope.  This means we’ll get the same instance of the class under test from our mocking kernel every time we request it until we call the kernel’s Reset method.

So, that eliminates the need for self-binding our class under test, but we still have the issue of the container returning brand new mocks every time we request one.  That’s because the container is using instance scope instead of singleton scope for the mocks.  Again, we can fix this by modifying the HanldeMissingBinding method, which should now look like this in its entirety:

protected override bool HandleMissingBinding(Type service)
{
    bool selfBindable = TypeIsSelfBindable(service);

    if (selfBindable)
    {
        Bind(service).ToSelf().InSingletonScope();
    }
    else
    {
        var binding = new Binding(service)
                          {
                              ProviderCallback = MockProvider.GetCreationCallback(),
                              ScopeCallback = ctx => Singleton,
                              IsImplicit = true
                          };

        AddBinding(binding);
    }


    return true;
}

With this change in place, both our test classes now pass!  You can check out this code on my ninject.moq fork on github.  I’ve submitted a pull-request, so hopefully the fixes will eventually be merged back into the main ninject.moq extension.

Using Ninject.Moq with SpecsFor<T>

With a working auto-mocking container in hand, all that remained was modifying SpecsFor to work with ninject.moq instead of StructureMap’s auto-mocking container.  I just swapped to the MockingKernel and explicitly created the class under test (StructureMap’s auto-mocking container creates the class under test for you automatically):

public abstract class SpecsFor<T> where T : class
{
    protected MockingKernel Mocker;

    protected T SUT { get; set; }

    /// <summary>
    /// Gets the mock for the specified type from the underlying container. 
    /// </summary>
    /// <typeparam name="TType"></typeparam>
    /// <returns></returns>
    protected Mock<TType> GetMockFor<TType>() where TType : class
    {
        return Mock.Get(Mocker.Get<TType>());
    }

    [TestInitialize]
    public virtual void SetupEachSpec()
    {
        InitializeClassUnderTest();

        Given();

        When();
    }

    protected virtual void InitializeClassUnderTest()
    {
        Mocker = new MockingKernel();

        ConfigureKernel(Mocker);

        SUT = Mocker.Get<T>();
    }

    protected virtual void ConfigureKernel(IKernel kernal)
    {
    }

    [TestCleanup]
    public virtual void TearDown()
    {
        Mocker.Reset();
        AfterEachSpec();
    }

    protected virtual void Given()
    {

    }

    protected virtual void AfterEachSpec()
    {

    }

    protected abstract void When();
}

Just to prove that it works, here’s the specs for SpecsFor (sadly using MS Test instead of NUnit.  Did you know there are people who actually use MS Test?  I didn’t either!) :)

public class SpecsForSpecs
{
    #region Dummy Classes

    public interface IDummyService
    {
        string GetSomeValue();
    }

    public class DummyClass
    {
        public IDummyService Service { get; set; }

        public DummyClass(IDummyService service)
        {
            Service = service;
        }
    }

    #endregion

    [TestClass]
    public class When_using_specs_for : given.the_default_state
    {
        protected override void When()
        {
            //Nothing to do
        }

        [TestMethod]
        public void Then_it_correctly_sets_up_the_class_under_test()
        {
            SUT.ShouldNotBeNull();
            SUT.Service.ShouldNotBeNull();
        }

        [TestMethod]
        public void Then_it_should_create_a_mock_service_for_the_dependency()
        {
            Mock.Get(SUT.Service).ShouldNotBeNull();
        }

        [TestMethod]
        public void Then_GetMock_should_always_return_the_same_mock()
        {
            GetMockFor<IDummyService>().ShouldBeSameAs(GetMockFor<IDummyService>());
        }
    }

    [TestClass]
    public class When_setting_up_expectations_on_a_mock : given.the_default_state
    {
        protected override void When()
        {
            GetMockFor<IDummyService>()
                .Setup(s => s.GetSomeValue()).Returns("I am a mocked result.");
        }
        
        [TestMethod]
        public void Then_the_expectations_are_called_when_the_mock_is_used()
        {
            SUT.Service.GetSomeValue().ShouldEqual("I am a mocked result.");
        }
    }

    public static class given
    {
        public abstract class the_default_state : SpecsFor<DummyClass>
        {
            
        }
    }
}

And there you have it!  A working Ninject auto-mocking container, and a version of SpecsFor that takes advantage of it.

On a related topic, I’m considering spinning SpecsFor into a lightweight library that can be easily reused.  Is there any interest in that?

Tags:

Feb 23 2010

Easily override ToString using Moq

Category: MoqMatt @ 05:40

I recently discovered a rather annoying limitation in Moq: you cannot setup expectations on the ToString method.  For a good discussion of the issue, check out Sean’s post.  His solution was to add ToString explicitly to the interface you are mocking, but I don’t want to dirty up my interfaces unnecessarily.  Fortunately, Moq does allow you to create mocks that implement multiple interfaces, so you could move the ToString method to a dummy interface, and use Mock<T>.As to setup expectations on the dummy interface.  That’s the approach I took, but I wrapped it up in a nice extension method:

public static class MoqExtensions
{
    public static ISetup<IToStringable, string> SetupToString<TMock>(this Mock<TMock> mock) where TMock : class
    {
        return mock.As<IToStringable>().Setup(m => m.ToString());
    }
    
    //Our dummy nested interface.
    public interface IToStringable
    {
        /// <summary>
        /// ToString.
        /// </summary>
        /// <returns></returns>
        string ToString();
    }
}

Now I can setup expectations on ToString by simply using:

[Test]
public void ExpectationOnToStringIsMet()
{
    var widget = new Mock<IWidget>();
    widget.SetupToString().Returns("My value").Verifiable();

    Assert.That(widget.Object.ToString(), Is.EqualTo("My value"));

    widget.Verify();
}

Tags:

Feb 22 2010

Extending Moq: returning multiple results via lambdas

Category: MoqMatt @ 05:06

I have on several occasions wished that I could setup expectations in Moq for subsequent calls to a method.  For example, I might want Moq to return one value the first time a method is called, but a different value the second and third times.  Phil Haack has a nice way to achieve this, but his implementation only allows you to return a result.  What if you need something more advanced?  What if you want to return a value on the first call, throw an exception on the second, and return a value again on the third?  I ran into exactly this situation while testing out some error-handling logic in a class.  Here’s how I achieved it.

public static class MoqExtensions
{
    public static IReturnsResult<TMockType> Returns<TMockType, TReturnType>(this IReturns<TMockType, TReturnType> expression, params Func<TReturnType>[] results) 
        where TMockType : class
    {
        int nextResult = 0;

        return expression.Returns(() => results[nextResult++]());
    }
}

This adds a new Returns method you can use with Moq in place of one of the built-in Return methods.  It allows you to specify an arbitrary number of Func’s to be executed.  Instead of using Moq to return the Func’s directly, it creates a new Func (via a lambda expression) that will iterate over the result Func’s specified.  It does this via a closure around the results and the index of the next result.  Note that it accepts a ‘params’ array, so calling it still looks (fairly) clean:

[Test]
public void ContinuesWorkingIfErrorEventIsHandled()
{
    mResultSet.Setup(r => r.GetNextResult()).Returns((Func<IResult>)(() => { throw new NotImplementedException(); }), () => null);

    //Run...
    
    mResultSet.Verify(r => r.GetNextResult(), Times.Exactly(2));
}

That’s all there is to it!

Tags: