AutoMocker in StructureMap 2.5

Steve Harman asked me yesterday to show a little demo of the AutoMocking container coming soon in StructureMap 2.5.  Honestly, I was very lukewarm to the idea of an “AutoMocking” container at first because I thought it would obfuscate tests.  Everyone else was doing it, so I figured I’d give it a shot too and I built an automocker into StructureMap.  I’m not entirely thrilled with the API as it stands, so any feedback would be very welcome.

My advice for the last four years has remained pretty consistent:  use StructureMap (or container of your choice) in unit tests very sparingly.  Just use plain Jane constructor injection inside your unit tests.  That advice aside, what you end up with is a lot of boring, repetitive code like this sample from StoryTeller that tests a class called WikiTextPresenter:

        private MockRepository _mocks;
        private IWikiTextEditor _editor;
        private ITestFormatConverter _converter;
        private WikiTextPresenter _presenter;

        [SetUp]
        public void SetUp()
        {
            _mocks = new MockRepository();
            _editor = _mocks.CreateMock<IWikiTextEditor>();
            _converter = _mocks.CreateMock<ITestFormatConverter>();

            _presenter = new WikiTextPresenter(_editor, _converter);
        }

It’s simple code, but it’s code that you write over and over and over again to do interaction testing.  Instead, what if we wrote something that can

  1. Look at the constructor of the WikiTextPresenter class being tested above
  2. See that it requires an IWikiTextEditor and an ITestFormatConverter in its constructor
  3. Create a mock object for each of WikiTextPresenter’s dependencies
  4. Poke all the mock objects into WikiTextPresenter for us
  5. And lastly, give us easy access to both the class under test and all the mock objects that the class under test depends on

That in a nutshell is an automocking container.

After seeing what the Eleutian guys were doing, I wanted something similar to their AutoMocking container just to eliminate the repetitious code of building mock objects and ramming them through a constructor function.  I built a new assembly in StructureMap called StructureMap.AutoMocking.  Inside it is a class called RhinoAutoMocker that extends the RhinoMocks MockRepository class with some StructureMap magic.  RhinoAutoMocker’s responsibility in life is to connect the right mocks and/or stubs to the class under test, freeing you from the monotonous code shown up above.  Specifically, you use a generic parameter to tell the RhinoAutoMocker what the concrete class under test is.  The class itself is below.  After the break, I’ll talk about usage.

    // Note that it subclasses the RhinoMocks.MockRepository class
    public class RhinoAutoMocker<TARGETCLASS> : MockRepository where TARGETCLASS : class
    {
        private readonly AutoMockedInstanceManager _manager;
        private TARGETCLASS _classUnderTest;

        public RhinoAutoMocker()
        {
            RhinoMocksServiceLocator locator = new RhinoMocksServiceLocator(this);
            _manager = new AutoMockedInstanceManager(locator);
        }

        // Replaces the inner InstanceManager in ObjectFactory with the mocked
        // InstanceManager from the auto mocking container.  This will make ObjectFactory
        // return mocks for everything.  Use cautiously!!!!!!!!!!!!!!!
        public void MockObjectFactory()
        {
            ObjectFactory.ReplaceManager(_manager);
        }

        // Gets the ClassUnderTest with mock objects (or stubs) pushed in
        // for all of its dependencies
        public TARGETCLASS ClassUnderTest
        {
            get
            {
                if (_classUnderTest == null)
                {
                    _classUnderTest = _manager.FillDependencies<TARGETCLASS>();
                }

                return _classUnderTest;
            }
        }

        // I find it useful from time to time to use partial mocks for the ClassUnderTest
        // Especially in Presenter testing
        public void PartialMockTheClassUnderTest()
        {
            _classUnderTest = PartialMock<TARGETCLASS>(getConstructorArgs());
        }

        private object[] getConstructorArgs()
        {
            ConstructorInfo ctor = Plugin.GetGreediestConstructor(typeof (TARGETCLASS));
            List<object> list = new List<object>();
            foreach (ParameterInfo parameterInfo in ctor.GetParameters())
            {
                Type dependencyType = parameterInfo.ParameterType;
                object dependency = _manager.CreateInstance(dependencyType);
                list.Add(dependency);
            }

            return list.ToArray();
        }

        // Get one of the mock objects that are injected into the constructor function
        // of the ClassUnderTest
        public T Get<T>()
        {
            return _manager.CreateInstance<T>();
        }

        // Set the auto mocking container to use a Stub for Type T
        public void InjectStub<T>(T stub)
        {
            _manager.InjectStub<T>(stub);
        }
    }

In usage it looks like this for the WikiTextPresenter class we looked at up top.  The test specifies that when ApplyChanges() is called on WikiTextPresenter, it will take the raw text from its view (IWikiTextEditor), convert that text to the internal data structure with ITestFormatConverter, and finally update some information in the View.

        [Test]
        public void ApplyChanges_with_the_automocker()
        {
            RhinoAutoMocker<WikiTextPresenter> mocks = new RhinoAutoMocker<WikiTextPresenter>();
            using (mocks.Record())
            {
                Test test = new Test();
                mocks.ClassUnderTest.TestPart = test;

                string theWikiText = "!|SomeFixture|";
                Expect.Call(mocks.Get<IWikiTextEditor>().WikiText).Return(theWikiText);

                WikiVersion expectedVersion = new WikiVersion(0, theWikiText);
                mocks.Get<ITestFormatConverter>().ApplyChangesFromWiki(test, theWikiText);
                mocks.Get<IWikiTextEditor>().AddWikiVersionToList(expectedVersion);
                mocks.Get<IWikiTextEditor>().SetWikiVersion(expectedVersion);
            }

            using (mocks.Playback())
            {
                mocks.ClassUnderTest.ApplyChanges();
            }
        }

RhinoAutoMocker creates the WikiTextPresenter instance under test on the first call to RhinoAutoMocker.ClassUnderTest.  The Get<T>() method on RhinoAutoMocker simply retrieves the mock object of type T that was used to construct the class under test.  Otherwise, all other usage is just the normal RhinoMocks usage.

In case you’re wondering, I chose RhinoMocks because:

  1. RhinoMocks is probably the most common mocking tool by a large margin.  It’s what I use, and I ultimately wanted a tool for me;)
  2. NMock/NMock2 seems to be dead.  I finally eliminated the direct NMock support from StructureMap for the 2.5 release anyway.
  3. If you’re using TypeMock you probably don’t care about dependency injection and automocking anyway

Making the RhinoAutoMocker subclass MockRepository just seemed like a good way to have all of the RhinoMocks capabilities right there at hand instead of wrapped up behind the scenes.

 

 

If you want to use this now, you need to download the very latest code out of StructureMap’s subversion repository at https://structuremap.svn.sourceforge.net/svnroot/structuremap/trunk.  Like I’ve said before, I’m basically done with coding on 2.5, but I’m not releasing officially until I can do a full rewrite of the website and documentation.

 

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.