Jeremy D. Miller -- The Shade Tree Developer

Sponsors

The Lounge

Syndication

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
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.

 


Posted Sat, Feb 9 2008 11:27 AM by Jeremy D. Miller
Filed under:

[Advertisement]

Comments

Aaron Jensen wrote re: AutoMocker in StructureMap 2.5
on Sat, Feb 9 2008 1:53 PM
Steven Harman wrote re: AutoMocker in StructureMap 2.5
on Sat, Feb 9 2008 3:30 PM

Awesome... thanks Jeremy!

I'm pulling down the latest bits now and I plan to play around with them a bit this weekend and then we'll be putting them to the test on a real-live project this coming week. I'll be sure to shoot you any feedback we come up with.

» Daily Bits - February 10, 2008 Alvin Ashcraft’s Daily Geek Bits: Daily links, development, gadgets and raising rugrats. wrote &raquo; Daily Bits - February 10, 2008 Alvin Ashcraft&#8217;s Daily Geek Bits: Daily links, development, gadgets and raising rugrats.
on Sun, Feb 10 2008 9:34 AM

Pingback from  &raquo; Daily Bits - February 10, 2008 Alvin Ashcraft&#8217;s Daily Geek Bits: Daily links, development, gadgets and raising rugrats.

e-tobi wrote re: AutoMocker in StructureMap 2.5
on Mon, Feb 11 2008 6:56 AM

Please use DynamicMock by default and allow to configure using the non-dynamic CreateMock where needed. See bug report #1888704 and the attached patch I posted last week.

Steve Freeman wrote re: AutoMocker in StructureMap 2.5
on Mon, Feb 11 2008 8:27 AM

Interesting idea, but surely the reduced set up is outweighed by the extra syntax in the test methods since you have to replace every case of _converter with _mocks.Get<ITestFormatConverter>() ?

b.t.w. it may not be relevant but NMock2 has just woken up again with a new set of committers

Jeremy D. Miller wrote re: AutoMocker in StructureMap 2.5
on Mon, Feb 11 2008 8:36 AM

@Steve,

CTRL-ALT-V and problem solved.  That is a valid concern though.

Jeremy D. Miller wrote re: AutoMocker in StructureMap 2.5
on Tue, Feb 12 2008 10:26 AM

@e-tobi:

DynamicMock it is.  I just checked in the change.

e-tobi wrote re: AutoMocker in StructureMap 2.5
on Tue, Feb 12 2008 10:50 AM

Thanks!

You didn't like the Mocking-Strategy patch which allows to change the default mocking strategy for each Service when required? (Just like the Windsor/Rhino.Mocks-AutoMocker does it)

Jeremy D. Miller wrote re: AutoMocker in StructureMap 2.5
on Tue, Feb 12 2008 11:00 AM

e-tobi,

I'll get your patch incorporated soon.

e-tobi wrote re: AutoMocker in StructureMap 2.5
on Tue, Feb 12 2008 11:20 AM

Great! But no need to hurry.

Sheraz wrote re: AutoMocker in StructureMap 2.5
on Fri, Feb 22 2008 9:29 AM

Sweeeet. I think I'm gonna give it a shot for Trade Capture :)

Colin Jack wrote re: AutoMocker in StructureMap 2.5
on Sun, Feb 24 2008 9:55 AM

"If you're using TypeMock you probably don't care about dependency injection and automocking anyway"

I wouldn't say that, or atleast I hope thats not the case. I've used TypeMock for a couple of years but I definitely care about DI, I just don't feel the need to use it everywhere.

Joshua Flanagan wrote The Rhino.Mocks' AssertWasCalled method does work
on Thu, Sep 25 2008 11:07 AM

This behavior is probably clearly specified somewhere, but somehow it has been non-obvious to the four

Automocking container with Moq - Daniel Cazzulino's Blog wrote Automocking container with Moq - Daniel Cazzulino's Blog
on Tue, Oct 14 2008 4:06 AM

Pingback from  Automocking container with Moq - Daniel Cazzulino's Blog

Elegant Code » Learning about StructureMap wrote Elegant Code &raquo; Learning about StructureMap
on Fri, Dec 12 2008 6:25 PM

Pingback from  Elegant Code &raquo; Learning about StructureMap

Recent Links Tagged With "rhinomocks" - JabberTags wrote Recent Links Tagged With "rhinomocks" - JabberTags
on Tue, Feb 24 2009 5:19 PM

Pingback from  Recent Links Tagged With "rhinomocks" - JabberTags

Dennis van der Stelt wrote re: AutoMocker in StructureMap 2.5
on Sat, Apr 11 2009 12:48 PM

"3.If you're using TypeMock you probably don't care about dependency injection and automocking anyway"

If you're just using dependency injection just for unit testing, you don't get DI.

I use Typemock Isolator for unit testing and I use DI for decoupling.

Add a Comment

(required)  
(optional)
(required)  
Remember Me?