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

Tim Barcz

Why use nails when a screw is the more reversible choice? Have Twitter, follow the conversation there at @timbarcz


Windsor Components, the ASP.NET MVC Framework, and Bug Verification Tests

Shhh...don't tell anyone but we don't unit test all of our code.  We're striving to get all developers and managers on board with unit testing but we're not there yet.  Despite our delinquency in writing tests one thing we do try our very best to do is keep mistakes from happening again.  If we find a bug in the system, before fixing it, we go and write a unit test for that problem.  We verify the test fails, the go and write the code that fixes it.  This recognizes that bugs will appear in the system, but once fixed we'll insulate ourselves from that bug happening again.

We had one such case last week.  We were getting a yellow-screen error after a bunch of commits by developers.  The error stemmed from a component in Windsor that did not have all of it's dependencies met.  In other words, we registered a component which relied on another component which was not registered.  We already had written a test to compile and test our Windsor configuration, however that test was not mature enough and needed some tweaking. 

In our application we leverage the new ASP.Net MVC.  We also take advantage of the ability to leverage an IoC container, Windsor, to create controller instances when a web request comes in.  When the application starts, we register all of the controllers in the application into Windsor using reflection.  Therefore our Windsor configuration at runtime is made up of two things, the XML configuration and the controllers which are registered on startup.  The "bug" here was that one of our controllers had a dependency on it that was not registered in Windsor.  When you ran the test by itself, the test would pass, since it was only loading up the components from the Windsor configuration.

Wanting to protect us in the future, we acknowledged there was something missing from our test and set out to find it.  To create the failing test was relatively simple.  All that we needed to do replicate in our test what we were doing at runtime.  Therefore we needed to register all implementers of IController, just like we do on application startup.  Below I've

Before:

   1: IWindsorContainer container = new WindsorContainer("windsor.config.xml");
   2:  
   3: foreach (var handler in container.Kernel.GetAssignableHandlers(typeof(object)))
   4: {
   5:     Console.WriteLine("{0}\n\t- {1}", handler.ComponentModel.Service, handler.ComponentModel.Implementation);
   6:     container.Resolve(handler.ComponentModel.Service);
   7: }

After:

   1: IWindsorContainer container = new WindsorContainer("windsor.config.xml");
   2:  
   3: var assm = new HomeController(null).GetType().Assembly;
   4: //add all controllers
   5: foreach (Type type in assm.GetTypes())
   6: {
   7:     if (typeof(IController).IsAssignableFrom(type) && !type.IsAbstract)
   8:     {
   9:         container.AddComponent(type.Name.ToLower(), type);
  10:     }
  11: }
  12:  
  13: foreach (var handler in container.Kernel.GetAssignableHandlers(typeof(object)))
  14: {
  15:     Console.WriteLine("{0}\n\t- {1}", handler.ComponentModel.Service, handler.ComponentModel.Implementation);
  16:     container.Resolve(handler.ComponentModel.Service);
  17: }

Now that this test is in place, I am much more confident that we won't see the error we were seeing in product again, we've got a test which warns us if something isn't quite right.  Our initial test didn't quite get it all right.  Mistakes/bugs in code will happen, hopefully few and far between, but when a bug does show up, go write a test that verifies the bug before going off an fixing it.  Then make the test pass, which should fix the bug.



Comments

Jeremy D. Miller said:

Psst...

If you were using StructureMap you could just do this:

ObjectFactory.AssertConfigurationIsValid()

and get an error report of all missing configuration and/or build failures in the container.

just saying...

# November 14, 2008 1:35 PM

Tim Barcz said:

@Jeremy,

Are you saying that I wouldn't have to do the foreach garbage over the "GetAssignableHandlers" call?

If so, that's a nice feature.  But don't speak too loudly or Ayende will swoop in and add that feature to Windsor.

Blog post I'd be interested in seeing for you or someone pro StructureMap is an evaluation of why one would want to switch from their current IoC container (Windsor for me) to StructureMap.  The way I look at it is, unless there is a definite benefit, then it's change for the sake of change.

Don't get me wrong, I'm not saying anything is wrong with StructureMap, but I'm really not up to speed on it.   As a Windsor user I'd be curious to see what you, or SM user, see as the benefits over Windsor.

Possible blog post?

# November 14, 2008 1:45 PM

Chris Canal said:

You can get rid of the ForEach with Castle:

container.Register(AllTypes.FromAssembly(Assembly.Load("AssemblyName")).BasedOn<IController>());

:)

# November 15, 2008 2:06 PM

Tim Barcz said:

@Chris

Thanks for the tip....I definitely appreciate it.

# November 15, 2008 2:17 PM

Dew Drop - Weekend Edition - November 15-16, 2008 | Alvin Ashcraft's Morning Dew said:

Pingback from  Dew Drop - Weekend Edition - November 15-16, 2008 | Alvin Ashcraft's Morning Dew

# November 15, 2008 9:42 PM

ASP.NET MVC Archived Blog Posts, Page 1 said:

Pingback from  ASP.NET MVC Archived Blog Posts, Page 1

# November 16, 2008 11:31 PM

Reflective Perspective - Chris Alcock » The Morning Brew #224 said:

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #224

# November 17, 2008 3:25 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors

Proudly Partnered With