Be wary of container calls in tests

This one cost me a couple of hours today.  To be clear:

No calls to the IoC container in a unit or integration test!

I want my tests to fail because of an assertion failure, not because of a setup failure.  Containers aren’t brittle, but they can be in a test, and an incorrectly configured container can cause an explosion of failures in tests.  That makes it very difficult to pinpoint a true failure.  There are plenty of patterns to set up fixtures and contexts – from the Builder pattern to the Object Mother pattern to a common Setup method.  All of these can set up the context of a test without using an IoC container.

I have tests for my container, but I have to be very, very wary of a container call in a test.  And no, I don’t use an auto-mocking container as well, I have yet to be convinced it’s better than Builder or Object Mother.  With those patterns, I can follow the yellow-brick road to exactly what’s being constructed.  Not so in the event of a container failure in a test.

If you’ve had luck with containers in a test, I’d love to hear about it.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in Testing. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Well put.

    In my experience, another good selling point as to why you shouldn’t use your container in your unit tests is just the fact that the container slows your tests down so much.

    My top 5 slowest running tests right now are all the tests around my actual container.

  • AMEN brotha! I couldn’t have said it better myself.

    I too have yet to use an auto-mocking container. I feel it makes it TOO easy to have a large number of depedencies and whether you should re-visit the intent of the SUT

  • Never got into auto-mocking. I tried, but I thought I was slow, because I never “got it”. Object Mother works fine for me and it clearly expresses what is necessary.

  • Eric Hexter

    I agree that you should not integration test through your IoC, But it is important to test your IoC explicitly. Do not take this advice and delete references to your container an assume that the containers autoconfiguration is doing what it is suppose to. The container still needs to be tested just like any other component of the system.

  • Newb Question: If I needed to test a service class, say ProductService that depends on a ProductRepository, UserService, AppService, etc. etc. etc. An IOC saves me a lot of typing in my tests, instantiating all those dependencies and applying them to the ProductService constructor every time I need to use the ProductService class. After reading this post, its obviously not the best thing to do. What is the best approach to this?

  • @Travis

    At that point, you’re really only looking at an interaction test. Each of the other pieces are abstractions, so there’s no real point in getting them all up and going.

    With test doubles, you can force your code down whatever path you like, without needing to set up your repository with the right data in the database, etc etc. This is assuming you’ve placed all your services behind interfaces, that is.

  • James

    How do you test multiple implementations of your repositories (or any interface that has multiple implementations) without duplicating your tests across multiple projects?

    For instance, say you have a SqlUserRepository and an ActiveDirectoryUserRepository ?

  • We use the IOC quite a bit in our integration tests. We have wrappers around Windsor that causes it to log out any errors it has when building an object.

    As of yet, we haven’t had big problems with the IOC, at least none that weren’t explicitly catching issues that couldn’t be caught by just wiring up the container. For example, someone forgot to set up serviceoverrides, so we weren’t getting the right implementation and tests were blowing up trying to use incorrect implementations.

    However, on the other hand, we had to spend a lot of time making sure that our integration tests painstakingly remove any data that they may put into the database, so that a failure in one integration test doesn’t cascade down into other ones using the same tables.

    Really, the biggest downfall is the infrastructure we’ve had to wrap our tests in to make sure that they’re atomic in terms of the DB. It can (not always, but sometimes) make things a little bit annoying when writing a new integration test.

  • @James

    Those are integration tests, but we still don’t get a container involved. Just a local creation method will work, passing the exact dependencies I want involved.

  • @mendicant

    One problem we ran into was not that our container threw exceptions, but rather was not configured completely correctly for a test. A failure occurred because the wrong piece was wired up. We do have container tests, which caught it, but a whole bunch of tests that failed with a lot of noise. Have you seen that?

  • With an auto-mocker, you also know exactly what is being constructed – your class under test. Any dependencies it has are mocks. There is no container configuration involved, and there shouldn’t be any mystery.
    Is there some other confusing aspect that I’m not recognizing?

  • @Josh

    I’m taking your Dovetail Kool-aid away from you. For me, AMC is solving a problem I don’t have. I don’t feel any pain manually creating mocks in tests, and I don’t have to go through something else to go get a reference to them. Show me (in a post hopefully) a side-by-side comparison of with/without AMC and tell me why I should care.

    What I was referring to was not AMC but using a Container to get “real” dependencies.

  • I get the point about not using a container in tests – the main intention of your post. It was only the throwaway jab at automocking that I was curious about.

    Anyway, explanation posted:

  • Jimmy,

    We have seen those sorts of things blow up like that, but we are using the IOC configured exactly the way it would be in production (except for logging, which is changed to the console) so I guess for us when it blows up like that, we take it as time to fix something that really needed to be fixed anyway. It’s usually a one time fix, and something that needed to be fixed not only for the integration test to run, but also for the app to run. I guess that makes it seem like less of a pain for us (and it really doesn’t happen that often).

  • @mendicant

    For what tests is the container in play?