Alan Dean

CTO, Developer, Agile Practitioner

Photograph of Alan Dean

Thursday, June 17, 2010

Mocking IServiceLocator

Using IoC has become far more popular in recent years but it is very easy to end up decoupling your components but at the same time end up tightly coupled to a specific provider, such as Castle Windsor. The first step to decouple the IoC provider is to utilize the Common Service Locator published by the Microsoft patterns & practices team. Here is a trivial example of decoupling using the ServiceLocator:

namespace Example
{
    using Microsoft.Practices.ServiceLocation;

    public interface IFoo
    {
        void Foo();
    }

    public sealed class FooImplementation : IFoo
    {
        public void Foo()
        {
        }
    }

    public sealed class Class1
    {
        public Class1()
        {
            this.Foo = ServiceLocator.Current.GetInstance<IFoo>();
        }

        public IFoo Foo
        {
            get;
            private set;
        }
    }
}

However, if you run the following test, a System.ArgumentNullException will be thrown as the ServiceLocator does not have a provider set:


namespace Example
{
    using Xunit;

    public sealed class Class1Facts
    {
        [Fact]
        public void ctor()
        {
            Assert.NotNull(new Class1());
        }
    }
}

Rather than configure a specific provider, it’s much cleaner to mock out the ServiceLocator. The following example uses Moq but the principle applies regardless of your preferred mocking framework:


namespace Example
{
    using Microsoft.Practices.ServiceLocation;
    using Moq;
    using Xunit;

    public sealed class Class1Facts
    {
        [Fact]
        public void ctor()
        {
            try
            {
                var mock = new Mock<IServiceLocator>();
                mock.Setup(x => x.GetInstance<IFoo>()).Returns(new FooImplementation()).Verifiable();
                ServiceLocator.SetLocatorProvider(new ServiceLocatorProvider(() => mock.Object));

                Assert.NotNull(new Class1());

                mock.VerifyAll();
            }
            finally
            {
                ServiceLocator.SetLocatorProvider(null);
            }
        }
    }
}

No comments: