Since learning (and loving) automated testing I have found myself using the dependency injection pattern in almost every project. Is it always appropriate to use this pattern when working with automated testing? Are there any situations were you should avoid using dependency injection?


10 Answers 10


Basically, dependency injection makes some (usually but not always valid) assumptions about the nature of your objects. If those are wrong, DI may not be the best solution:

  • First, most basically, DI assumes that tight coupling of object implementations is ALWAYS bad. This is the essence of the Dependency Inversion Principle: "a dependency should never be made upon a concretion; only upon an abstraction".

    This closes the dependent object to change based on a change to the concrete implementation; a class depending upon ConsoleWriter specifically will need to change if output needs to go to a file instead, but if the class were dependent only on an IWriter exposing a Write() method, we can replace the ConsoleWriter currently being used with a FileWriter and our dependent class wouldn't know the difference (Liskhov Substitution Principle).

    However, a design can NEVER be closed to all types of change; if the design of the IWriter interface itself changes, to add a parameter to Write(), an extra code object (the IWriter interface) must now be changed, on top of the implementation object/method and its usage(s). If changes in the actual interface are more likely than changes to the implementation of said interface, loose coupling (and DI-ing loosely-coupled dependencies) can cause more problems than it solves.

  • Second, and corollary, DI assumes that the dependent class is NEVER a good place to create a dependency. This goes to the Single Responsibility Principle; if you have code which creates a dependency and also uses it, then there are two reasons the dependent class may have to change (a change to the usage OR the implementation), violating SRP.

    However, again, adding layers of indirection for DI can be a solution to a problem that doesn't exist; if it is logical to encapsulate logic in a dependency, but that logic is the only such implementation of a dependency, then it is more painful to code the loosely-coupled resolution of the dependency (injection, service location, factory) than it would be to just use new and forget about it.

  • Lastly, DI by its nature centralizes knowledge of all dependencies AND their implementations. This increases the number of references that the assembly which performs the injection must have, and in most cases does NOT reduce the number of references required by actual dependent classes' assemblies.

    SOMETHING, SOMEWHERE, must have knowledge of the dependent, the dependency interface, and the dependency implementation in order to "connect the dots" and satisfy that dependency. DI tends to place all that knowledge at a very high level, either in an IoC container, or in the code that creates "main" objects such as the main form or Controller which must hydrate (or provide factory methods for) the dependencies. This can put a lot of necessarily tightly-coupled code and a lot of assembly references at high levels of your app, which only needs this knowledge in order to "hide" it from the actual dependent classes (which from a very basic perspective is the best place to have this knowledge; where it's used).

    It also normally doesn't remove said references from lower down in code; a dependent must still reference the library containing the interface for its dependency, which is in one of three places:

    • all in a single "Interfaces" assembly that becomes very application-centric,
    • each one alongside the primary implementation(s), removing the advantage of not having to recompile dependents when dependencies change, or
    • one or two apiece in highly-cohesive assemblies, which bloats the assembly count, dramatically increases "full build" times and decreases application performance.

    All of this, again to solve a problem in places where there may be none.

  • 1
    SRP = single responsibility principle, for anyone else wondering. Commented Feb 22, 2012 at 17:26
  • 1
    Yes, and LSP is the Liskov Substitution principle; given a dependency on A, the dependency should be able to be met by B which derives from A without any other change.
    – KeithS
    Commented Feb 22, 2012 at 17:29
  • 1
    the dependency injection specifically help where you need to get class A from class B from class D etc. in that case ( and only that case) the DI framework may generate less assembly bloat than poor's man injection. also I never had a bottleneck caused by DI.. think to maintenance cost, never to cpu cost because code can always be optimized , but doing that without a reason has a cost Commented Dec 1, 2014 at 23:05
  • Would another assumption be "if a dependancy changes it changes everywhere"? Or else you have to look at all consuming classes anyway Commented Oct 25, 2015 at 10:14
  • 6
    This answer fails to address the testability impact of injecting dependencies versus hardcoding them. See also the Explicit Dependencies Principle (deviq.com/explicit-dependencies-principle )
    – ssmith
    Commented May 25, 2017 at 18:43

Outside of dependency-injection frameworks, dependency injection (via constructor injection or setter injection) is very nearly a zero-sum game: you decrease the coupling between object A and it's dependency B, but now any object that needs an instance of A must now also construct object B.

You've slightly reduced the coupling between A and B, but reduced A's encapsulation, and increased coupling between A and any class that must construct an instance of A, by coupling them to A's dependencies as well.

So dependency injection (without a framework) is about equally harmful as it is helpful.

The extra cost is often easily justifiable, however: if the client code knows more about how to construct the dependency than the object itself does, then dependency injection really does reduce coupling; for example, a Scanner doesn't know much about how to obtain or construct an input stream to parse input from, or what source the client code wants to parse input from, so constructor injection of an input stream is the obvious solution.

Testing is another justification, in order to be able to use mock dependencies. That should mean adding an extra constructor used for testing only that allows dependencies to be injected: if you instead change your constructors to always require dependencies to be injected, suddenly, you have to know about your dependencies' dependencies' dependencies in order to construct your direct dependencies, and you can't get any work done.

It can be helpful, but you should definitely ask yourself for each dependency, is the testing benefit worth the cost, and am I really going to want to mock this dependency while testing?

When a dependency-injection framework is added, and the construction of dependencies is delegated not to client code but instead to the framework, the cost/benefit analysis changes greatly.

In a dependency-injection framework, the tradeoffs are a bit different; what you're losing by injecting a dependency is the ability to know easily what implementation you are relying on, and shifting the responsibility for deciding what dependency you are relying on to some automated resolution process (e.g. if we require an @Inject'ed Foo, there must be something that @Provides Foo, and whose injected dependencies are available), or to some high-level configuration file that prescribes what provider should be used for each resource, or to some hybrid of the two (for example, there may be an automated resolution process for dependencies that can be overridden, if necessary, using a configuration file).

As in constructor injection, I think the advantage of doing so ends up, again, being very similar to the cost of doing so: you don't have to know who is providing the data you rely on, and, if there are multiple potential providers, you don't have to know the preferred order to check for providers in, make sure that every location that needs the data checks for all potential providers, etc., because all of that is handled at a high level by the dependency injection platform.

While I don't personally have a great deal of experience with DI frameworks, my impression is that they provide more benefit than cost when the headache of finding the correct provider of the data or service that you need has a higher cost than the headache, when something fails, of not immediately knowing locally what code provided the bad data that caused a later failure in your code.

In some cases, other patterns that obscure dependencies (e.g. service locators) had already been adopted (and perhaps also proven their worth) when DI frameworks appeared on the scene, and the DI frameworks were adopted because they offered some competitive advantage, such as requiring less boilerplate code, or potentially doing less to obscure the provider of dependency when it becomes necessary to determine what provider is actually in use.

  • 10
    Just a quick comment about the dependency mocking in tests and "you have to know about your dependencies' dependencies' dependencies"... That's not true at all. One does not need to know or care about some concrete implementation's dependencies if a mock is being injected. One only needs to know about the direct dependencies of the class under test, which are satisfied by the mock(s).
    – Eric King
    Commented Feb 21, 2012 at 21:36
  • 10
    You misunderstand, I'm not talking about when you inject a mock, I'm talking about the real code. Consider class A with dependency B, which in turn has dependency C, which in turn has dependency D. Without DI, A constructs B, B constructs C, C constructs D. With construction injection, to construct A, you must first construct B, to construct B you must first construct C, and to construct C you must first construct D. So class A now has to know about D, the dependency of a dependency of a dependency, in order to construct B. This leads to excessive coupling. Commented Feb 22, 2012 at 16:33
  • 2
    There wouldn't be so much cost to having an extra constructor used for testing only that allows the dependencies to be injected. I'll try to revise what I said. Commented Feb 22, 2012 at 16:37
  • 7
    Dependency injection dosent only move dependencies around in a zero sum game. You move your dependencirs to places they already exist: the main project. You can even use convention-based approaches to make sure the dependencies are only resolved at run time, for instance by specifying which classes are concrete by namespaces or whatever. I have to say this is a naive answer
    – Sprague
    Commented Apr 24, 2016 at 11:22
  • 5
    @Sprague Dependency injection moves around dependencies in a slightly negative-sum game, if you apply it in cases where it shouldn't be applied. The purpose of this answer is to remind people that dependency injection is not inherently good, it is a design pattern that is incredibly useful in the right circumstances, but an unjustifiable cost in normal circumstances (at least in the programming domains I've worked in, I understand in some domains it's more frequently useful than in others). DI sometimes becomes a buzzword and an end in itself, which misses the point. Commented Apr 25, 2016 at 20:14
  1. if you are creating database entities, you should rather have some factory class which you will inject instead to your controller,

  2. if you need to create primitive objects like ints or longs. Also you should create "by hand" most of the standard library objects like dates, guids, etc.

  3. if you would like to inject configuration strings it's probably better idea to inject some configuration objects (in general it is recommended to wrap simple types into meaningful objects: int temperatureInCelsiusDegrees -> CelciusDeegree temperature)

And don't use Service locator as dependency injection alternative, it's anti-pattern, more info: http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

  • All the points are about using different form of injection rather than not using it altogether. +1 for the link though.
    – Jan Hudec
    Commented Sep 23, 2013 at 15:02
  • 3
    Service Locator is NOT an anti-pattern and the guy who's blog you linked to is not an expert in patterns. That he got StackExchange-famous is kind of a disservice to software design. Martin Fowler (author of staple Patterns of Enterprise Application Architecture) has a more reasonable view on the matter: martinfowler.com/articles/injection.html
    – Colin
    Commented Apr 11, 2016 at 21:52
  • 3
    @Colin, on the contrary, Service Locator is most definitely an anti-pattern, and here in a nutshell is the reason why.
    – Kyralessa
    Commented Jul 29, 2019 at 14:50
  • @Kyralessa - you realize that DI frameworks internally use a Service Locator pattern to look up services, right? There are circumstances where both are appropriate, and neither are an anti pattern despite the StackExchange hate some people want to dump.
    – Colin
    Commented Jul 29, 2019 at 18:38
  • Sure, and my car internally uses pistons and spark plugs and a host of other things which are not, however, a good interface for an ordinary human being who just wants to drive a car.
    – Kyralessa
    Commented Jul 30, 2019 at 7:30

When you don't stand to gain anything by making your project maintainable and testable.

Seriously, I love IoC and DI in general, and I'd say that 98% of the time I will use that pattern without fail. It's especially important in a multi-user environment, where you code can be reused again and again by different team members and different projects, as it separates logic from implementation. Logging is a prime example of this, an ILog interface injected into a class is a thousand times more maintainable than simply plugging in your logging framework-du-jour, as you have no guarantee another project will use the same logging framework (if it uses one at all!).

However, there are times when it is not an applicable pattern. For example, functional entry points that are implemented in a static context by a non-overridable initialiser (WebMethods, I'm looking at you, but your Main() method in your Program class is another example) simply cannot have dependencies injected at initialisation time. I'd also go as far as to say that a prototype, or any throw-away investigative piece of code, is also a bad candidate; the benefits of DI are pretty much mid-to-long-term benefits (testability and maintainability), if you are certain that you will throw away the majority of a piece of code within a week or so I would say you gain nothing by isolating dependencies, just spend the time you'd normally spend testing and isolating dependencies getting the code working.

All in all, it's sensible to take a pragmatic approach to any methodology or pattern, as nothing is applicable 100% of the time.

One thing to note is your comment about automated testing: my definition of this is automated functional tests, for example scripted selenium tests if you are in a web context. These are generally completely black-box tests, with no need to know about the inner workings of the code. If you were referring to Unit- or Integration-tests I'd say that the DI pattern is almost always applicable to any project that heavily relies on that kind of white-box testing, since, for example, it allows you to test things like methods that touch the DB without any need for a DB to be present.

  • I don't understand what you mean about logging. Surely all loggers aren't going to conform to the same interface so you'd have to write your own wrapper to translate between this projects way of logging and a specific logger (assuming you wanted to be able to easily change loggers). So after that what does DI give you? Commented Oct 25, 2015 at 10:27
  • @RichardTingle I'd say that you should define your logging wrapper as an interface, and then you write an lightweight implementation of that interface for each external logging service, instead of using a single logging class that wraps multiple abstractions. It's the same concept you're proposing but abstracted at a different level.
    – Ed James
    Commented Oct 28, 2015 at 16:03
  • DI can help testability in a compiled language by enabling mocking. In an interpreted language, mocking comes out of the box, so this aspect of DI is not a valid argument in the context of interpreted languages. Commented Jan 17, 2022 at 22:40

I suggest you to try to use just basic OOP principles: use inheritance to extract common functionality, encapsulate/hide things that should be protected from outside world using private/internal/protected members/types. Use any powerful enough test-framework to inject code for tests only, for example https://www.typemock.com/ or https://www.telerik.com/products/mocking.aspx .

Next, try to re-write that using DI and then compare the code. What you will usually see having DI:

  1. You have more interfaces (more types)
  2. You've created signature duplicates of your public methods and you will have to double maintain it (you can't simply change a parameter once, you will have to do it twice. Basically all refactoring and navigational possibilities become more complicated with DI)
  3. You exchanged some of compilation errors to runtime failures (with DI it's easy to ignore a missing dependency while coding, and not surely it is going to be exposed when testing)
  4. You've uncovered your encapsulation. Now protected members,internal types and others have became public
  5. Overall code-base is bigger with DI

From what I've seen, almost always, code quality goes down with DI.

However, if you use only "public" access modifier in class declaration, and/or public/private modifiers for members, and/or you don't have a choice to buy expensive test tools and same time you need unit testing that can't be replaced by integrational testing, and/or you already have interfaces for the classes you are thinking to inject, DI is a good choice! It works great where plugins are required, for instance.

p.s. probably I will get number of minuses for this post, but I believe that's because of most modern developers just don't care about how and why to use internal keyword, for example, or how to decrease coupling of your components and finally why to decrease it. Eventually, just try to code and compare.

  • 1
    I don't know about minuses, but I would give additional pluses if I could.
    – foo
    Commented Jan 17, 2023 at 13:49
  • 1
    @foo thank you for reminding. I have fixed the answer slightly. Just improved English and language style mostly. Commented Jan 20, 2023 at 9:47

While the other answers focus on the technical aspects I would like to add a practical dimension.

Over the years I came to a conclusion that there are several practical requirements that need to be met if introducing Dependency Injection is to be a success.

  1. There should be a reason to introduce it.

    This sounds obvious, but if your code only gets things from the database and returns it without any logic then adding a DI container makes things more complex with not real benefit. Integration testing would be more important here.

  2. The team needs to be trained and on board.

    Unless the majority of the team is on board and understands DI adding inversion of control container becomes a yet another way to do things and made the code base even more complicated.

    If the DI is introduced by a new member of the team, because they understand it and like it and just want to show that they are good, AND the team is not actively involved, there is a real risk that it will actually decrease quality of the code.

  3. You need to test

    While decoupling is generally a good thing, DI can move resolution of a dependency from compile time to run time. This is actually quite dangerous if you don't test well. Run time resolution failures can be costly to track and resolve.
    (It is clear from your test that you do, but many teams don't test to the extent that is required by DI.)


This is not a complete answer, but just another point.

When you have an application that start once, runs for a long time (like a web app) DI might be good.

When you have an application that starts many times and runs for shorter times (like a mobile app) you probably do not want the container.

  • I don’t see how live time of application related to DI Commented May 14, 2018 at 22:21
  • @MichaelFreidgeim It takes time to initialise the the context, usually DI containers are quite heavy, such as Spring. Make a hello world app with just one class and make one with Spring and start both 10 times and you will see what I mean. Commented May 14, 2018 at 23:43
  • It sound like an issue with an individual DI container. In .Net world I haven’t heard about initialisation time as an essential problem for DI containers Commented May 16, 2018 at 21:58

An alternative to Dependency Injection is using a Service Locator. A Service Locator is easier to understand, debug, and makes constructing an object simpler especially if you aren't using a DI framework. Service Locators are a good pattern for managing external static dependencies, for instance a database that you would otherwise have to pass into every object in your data access layer.

When refactoring legacy code, it is often easier to refactor to a Service Locator than to Dependency Injection. All you do is replace instantiations with service lookups and then fake out the service in your unit test.

However, there are some downsides to the Service Locator. Knowing the depandancies of a class is more difficult because the dependencies are hidden in the class's implementation, not in constructors or setters. And creating two objects that rely on different implementations of the same service is difficult or impossible.

TLDR: If your class has static dependencies or you are refactoring legacy code, a Service Locator is arguably better than DI.

  • 12
    The Service Locator hides dependencies in your code. It's not a good pattern to use.
    – Kyralessa
    Commented Feb 20, 2012 at 23:10
  • 1
    When it comes to static dependencies, I'd rather see facades slapped on them that implement interfaces. These can then be dependency injected, and they fall on the static grenade for you. Commented Feb 21, 2012 at 0:26
  • @Kyralessa I agree, a Service Locator has many downsides and DI is almost always preferable. However, I believe there are a couple exceptions to the rule, as with all programming principles. Commented Feb 21, 2012 at 14:13
  • Service location's main accepted use is within a Strategy pattern, where a "strategy picker" class is given enough logic to find the strategy to use, and either hand it back or pass a call through to it. Even in this case, the strategy picker can be a facade for a factory method provided by an IoC container, which is given the same logic; the reason you'd break it out is to put logic where it belongs and not where it's most hidden.
    – KeithS
    Commented Feb 21, 2012 at 19:18
  • 2
    To quote Martin Fowler, "The choice between (DI and Service Locator) is less important than the principle of separating configuration from use". The idea that DI is ALWAYS better is hogwash. If a service is used globally, it's more cumbersome and brittle to use DI. Additionally, DI is less favorable for plugin architectures where implementations aren't known till runtime. Think how awkward it would be to always pass additional arguments to Debug.WriteLine() and the like!
    – Colin
    Commented Apr 11, 2016 at 21:35

There's an scenario which not a lot of people seems to notice. Say we have the canonical calculator:

class Calculator 
    public Calculator (TrigonometryEngine trigonometryEngine ) {
       _trigonometryEngine = trigonometryEngine;

public decimal CosineOf(Radian radians) {
    return _trigonometryEngine.CosineOf(radians);


If we were to package this silly type as a library, it would impose a requirement on the consumer to understand how to build a TrigonometryEngine. However, the TrigonometryEngine is only an implementation detail and should not be included in the shipping API unless there is a clear motivation from the library writer that it can be replaced by consumers to adhere to the well known open-close principle. Otherwise, adding it to the API surface would only expand it unnecessarily, serving no other purpose than to facilitate smoother unit testing.

This aspect is systematically overlooked. Quite often, this leads to tests coupled to implementation details, ossifying the types relationships and making refactoring much more complex, as test safety net will become red for the wrong reasons.


I don't see this argument in other answers, so I'll add it.

Most dependency injection frameworks are multi-threaded solutions. Therefore, you should not use dependency injection with static classes that are not tread safe by default. First, make them tread safe.


Static constructor leads to The Ambient Context Anti-Pattern:


Ambient Context Anti-Pattern exploits many of the disadvantages discussed in other answers.

Not the answer you're looking for? Browse other questions tagged or ask your own question.