CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

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.

 



Comments

Steven Harman said:

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.

# February 9, 2008 3:30 PM

» Daily Bits - February 10, 2008 Alvin Ashcraft’s Daily Geek Bits: Daily links, development, gadgets and raising rugrats. said:

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

# February 10, 2008 9:34 AM

e-tobi said:

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.

# February 11, 2008 6:56 AM

Steve Freeman said:

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

# February 11, 2008 8:27 AM

Jeremy D. Miller said:

@Steve,

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

# February 11, 2008 8:36 AM

Jeremy D. Miller said:

@e-tobi:

DynamicMock it is.  I just checked in the change.

# February 12, 2008 10:26 AM

e-tobi said:

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)

# February 12, 2008 10:50 AM

Jeremy D. Miller said:

e-tobi,

I'll get your patch incorporated soon.

# February 12, 2008 11:00 AM

e-tobi said:

Great! But no need to hurry.

# February 12, 2008 11:20 AM

Sheraz said:

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

# February 22, 2008 9:29 AM

Colin Jack said:

"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.

# February 24, 2008 9:55 AM

Joshua Flanagan said:

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

# September 25, 2008 11:07 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

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 previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

Our Sponsors

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP