The Dangers Of AutoMocking Containers

Louis Salin commented on my original post about the Ninject.RhinoMocks automocking container, and brought up a very good point. Here is his comment, reproduced in full:

I’ve heard (or read…) that automocking is equivalent to taking weight loss pills while still eating cheesburgers for breakfast. Okay, I just made that up!

My point is, and I’m in no way in a position to opine on the matter, that the pain of mocking might be due to design issues. Hiding the pain with a tool won’t make the cause go away.

So maybe in this case it’s a very benign use of an automocker, but as the code base grows, the automocker will hide pain points that would otherwise become immediately obvious, no?

Louis has a good point and it is one that I have argued in the past to justify why I have not used an auto mocking container. However, I stand by my response in the comments of that post:

yeah, that’s the "big problem" that people complain about when they say auto mocking containers are bad. honestly, that’s a pretty weak excuse for not teaching developers how to spot too many dependencies as a part of bad design. trust your team. if they get it wrong, teach them right.

The “pain of mocking” that Louis is referring to is most often the need to mock a significant number of things in order to get a class spun up for testing. It may be painful or tedious or however you want to describe it, to get all of the things you need setup in order to get a class under test. But just because you can ignore that pain with an automocking container, doesn’t mean you will.

Before I expand on my response, though, let’s look at an example of what the problem really is.

 

A Simple Specification

This is the same sample specification that I ended yesterday’s blog post with. It’s small, easy to read and easy to understand. There is nothing really wrong with this code, in my opinion.

   1: public class when_doing_something_with_that_thing : ContextSpecification<MyPresenter>

   2: {

   3:     protected override void When()

   4:     {

   5:         SUT.DoSomething();

   6:     }

   7:     

   8:     [Test]

   9:     public void it_should_do_that_thing()

  10:     {

  11:         AssertWasCalled<IMyView>(v => v.ThatThing());

  12:     }

  13:  

  14:     [Test]

  15:     public void it_should_do_the_other_thing_twice()

  16:     {

  17:         AssertWasCalled<IMyView>(v => v.TheOtherThing(), mo => mo.Repeat.Twice());

  18:     }

  19: }

The problem that an automocking container hides is not this code, but what this code potentially hides in the implementation.

 

A Complex Implementation

Now take a look at one possibility for the implementation of the MyPresenter class used in the above specification:

   1: public class MyPresenter

   2: {

   3:     private IMyView view;

   4:     private ISomeService someService;

   5:     private IAnotherService anotherService;

   6:     private IMoreService moreService;

   7:     private ISomeRepository someRepository;

   8:     private IAnotherRepository anotherRepository;

   9:     private IMoreRepository moreRepository;

  10:     private IValidator<SomeData> someDataValidator;

  11:     private IValidator<MoreData> moreDataValidator;

  12:     private IValidator<AnotherData> anotherDataValidator;

  13:     private SomeData someData;

  14:     private AnotherData anotherData;

  15:     private MoreData moreData;

  16:     

  17:     public MyPresenter(

  18:         IMyView view,

  19:         ISomeService someService,

  20:         IAnotherService anotherService,

  21:         IMoreService moreService,

  22:         ISomeRepository someRepository,

  23:         IAnotherRepository anotherRepository,

  24:         IMoreRepository moreRepository,

  25:         IValidator<SomeData> someDataValidator,

  26:         IValidator<MoreData> moreDataValidator,

  27:         IValidator<AnotherData> anotherDataValidator

  28:     )

  29:     {

  30:         this.view = view;

  31:         this.someService = someService;

  32:         this.anotherService = anotherService;

  33:         this.moreService = moreService;

  34:         this.someRepository = someRepository;

  35:         this.anotherRepository = anotherRepository;

  36:         this.moreRepository = moreRepository;

  37:         this.someDataValidator = someDataValidator;

  38:         this.moreDataValidator = moreDataValidator;

  39:         this.anotherDataValidator = anotherDataValidator;

  40:     }

  41:     

  42:     // ... methods and implementation details go here

  43: }

That’s 40 lines of code just to get the object constructed! ARGH! that’s AWFUL! There are so many things wrong with just the member variables listed in the constructor of this class… and I haven’t even begun to imagine what the implementation of any methods on this class may look like. Quite honestly, I don’t want to think about what they may look like.

Now imagine that this code uses a couple of abstract base classes instead of all interfaces for the dependencies. Replace the three validators, for example, with abstract base classes. What happens when each of these base classes requires 2 constructor arguments for their own dependencies? The auto mocking container will go ahead and wire them up as well, and pass them into the abstract base classes so that the objects can be mocked. Now, instead of having 10 objects being mocked, we have 16. If any of those dependencies are objects with their own dependencies… well, I think you get the picture. The object graph being automocked in this scenario is horrendous and wreaks of bad design left and right.

But because we have an automocking container, we don’t care about that bad design, right? We’ll just let it slip and go on about our business because the pain of that horrendous mess is hidden away at test time. Our tooling of choice makes it easy to get away with poor design… or so the argument goes.

 

The Truth About Auto Mocking Containers

There is nothing inherently evil in auto mocking containers. They are not “bad” and using them is not “wrong”. Sure, they can be abused and you can do damage with them. The same thing is true of baseball bats, eggs, automatic rifles, and thousands upon thousands of other tools. Scott Bellware has quoted Ani DeFranco on the subject of tools, more than a few times: “every tool is a weapon if you hold it right”. 

Now… let me restate my opinion on the problem that Louis is referring to, keeping in mind that I used to cite this exact reason for my not wanting to use an auto mocking container.

Auto mocking containers do not facilitate poor design or horrendous implementation. Poor design and horrendous implementation skill, in the person designing and implementing the code, does.

That’s it, right there. The notion that an automocking container will let someone design and implement that pile of garbage, while not using one won’t let them or will expose the problem, is ridiculous.

Speaking as a person who used to write garbage like this (and still does, occasionally, I’ll admit), I know that not using an automocking container will not prevent you from doing this. It will not make the problems more obvious if you don’t use an automocking container, and you will not inherently write better code without one. A software developer who writes code like this is not going to know the problems they are causing just because they have to declare and instantiate the 10 mock objects that this code needs to be tested. Developers write code like this because that’s the kind of code they right… no other reason. Now, there might be a lot of reasons why they write code like this… but that’s a completely different set of subjects.

“a poor craftsman blames his tools” … “with great power comes great responsibility” … “(insert other overused and abused quotes here)”

 

One Last Note

I wanted to note, specifically, that this post is not directed at Louis or anyone in particular. Louis is only the guy that prompted the discussion and not a person that I would single out for writing bad code.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, Analysis and Design, AntiPatterns, AutoMocking, C#, Craftsmanship, Quality. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.lostechies.com/members/louissalin/default.aspx Louis Salin

    We are both right! :)

    Automocking will not prevent you from doing bad design. In the same way, unit testing will not prevent you from creating bugs in your software.

    I choose not to automock. But that’s because I know that mocking pains hide design flaws. Of course, somebody who’s oblivious to that will just thing that mocking in general is a pain and might stop unit testing as a consequence. So using the pain to discover flaws require that you know the relationship between the two of them.

    (in the following paragraph, I use the word “you” to mean everybody, not you specifically, Derick)
    But knowing all of that, how can you use an automocker? Are you so confident in your own abilities to know you’ll never have too many dependencies? Or that you’ll always be able to refactor later if you ever find out? Yeah… later… When we rewrite the app in a new language! We’ll take care of them dependencies then! :)

  • Dennis Kozora

    Perhaps managing dependencies can be better served by a build process using a tool like NDepend to alert a team “you have too many dependencies”.

  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    @Louis,

    by that logic, you should never trust any developer to do anything right. you should provide prescriptive frameworks that force your team members to only work in one very specific way, all the time.

    … fallacy… if you can’t trust your team members to use a chainsaw without cutting their own arms and legs off, then you need to train them in chainsaw safety before letting them lose. the same goes for writing code and creating good design in code.

    “Are you so confident in your own abilities to know you’ll never have too many dependencies?” … if you can’t recognize the problem when you look at the implementation of a class, you are not going to recognize the problem by having to manually mock the dependencies of that class, either.

    @Dennis,

    that might be useful for after-the-fact inspection / verification… but that’s quality inspection instead of defect prevention. in this case, the cost of fixing a problem found through quality inspection is likely to be much higher than the cost to prevent the problem in the first place.

    it’s the same problem with doing code reviews after something has already been written – most people are unwilling to go back and re-write anything of significance after it’s been written once… which is why code reviews tend to be shallow and gloss over major design problems

    by the same notion, telling someone they have too many dependencies with a static analysis tool like ndepend is going to be too late. the person is not going to want to hear it because they don’t want to or don’t have the time to go back and rewrite things.

    but we can avoid those types of situations by teaching a team about good design, how to recognize design problems and by doing design reviews before and during implementation, the amount of time spent on those reviews has to be commensurate to the risk and size of work being done, of course… a 3 hour review of a 10 minute code change is probably unreasonable, and a 10 minute review before a 3 week effort is probably not enough review. it’s an iterative, on-going process. … many would say the best way to do this is continuous review via pair programming… but not every team has that skillset or capability.

  • http://www.proace.com/blog Josh Arnold

    I’m with you on this one, Derick. While I admit that it has the potential to “hide” certain things, I’ve always seen it as a tool that enables me to test the behaviors of my classes a lot faster and with less friction.

    Perhaps the underlying debate here is the fact that it can potentially hide compilation errors when you specify additional dependencies? It may work great when you’re applying a TDD approach but of course it hides SRP violations later on…I’d still prefer an approach that reduces friction in testing though despite that possibility. Besides, we’re never going to have the time/budget to implement everything perfectly anyway. Why use a testing approach that’s inflexible?

    I guess I’m just not seeing the issue here.

  • http://gillesleblanc.wordpress.com/ Gilles Leblanc

    Great post. I have started using an auto mocking container myself and had asked myself the question if dependencies that can be automocked aren’t a sign of bad design. Someone else recently said to me a similar thing after a blogged on AutoMoq. While I can see situation where these automockable dependencies aren’t a sign of bad design I still had interrogations. Your post help me with my thinking reflexion on the subject. Thanks.